// ==UserScript== // @name 🌟适合【2025国家智慧教育平台寒假研修】【河北继续教育-师学通 | 中国教育电视台(2024中小学) | 奥鹏 | 高等教育出版社(2024中小学)】无人值守/极速刷课 // @namespace http://tampermonkey.net/zzzzzzys_国家中小学 // @version 2.2.1 // @copyright zzzzzzys.All Rights Reserved. // @description 适用2025国家智慧教育平台、河北继续教育【师学通、2024中小学、奥鹏】.✅ 中小学/师范生:课程目录页秒刷视频🚀 职业教育/高等教育:三倍速自动挂机播放💎师学通全自动支持:课程连刷 | 防暂停 | 验证码破解💎2024中小学全自动支持/秒学💎奥鹏全自动 【新增】高等教育出版社(2024中小学) 全自动/秒学📢 注意:禁止二次发布!加QQ群获取更新 // @author zzzzzzys // @match https://basic.smartedu.cn/* // @match https://core.teacher.vocational.smartedu.cn/* // @match https://test3.ykt.eduyun.cn/* // @match https://pn202413060.stu.teacher.com.cn/studyPlan/* // @match https://pn202413060.stu.teacher.com.cn/course/* // @match https://cn202511002.stu.t-px.cn/* // @match http://cas.study.yanxiu.jsyxsq.com/auth/selfHost/studyPlace/index.html* // @match https://learn.ourteacher.com.cn/StepLearn/StepLearn/* // @match https://vc.chinabett.com/studyduration/index* // @require https://fastly.jsdelivr.net/npm/crypto-js@4.2.0/crypto-js.min.js // @resource https://cdn.staticfile.org/limonte-sweetalert2/11.7.1/sweetalert2.min.css // @require https://fastly.jsdelivr.net/npm/sweetalert2@11.12.2/dist/sweetalert2.all.min.js // @connect basic.smartedu.cn // @connect x-study-record-api.ykt.eduyun.cn // @connect fc-mp-8ba0e2a3-d9c9-45a0-a902-d3bde09f5afd.next.bspapp.com // @connect mp-8ba0e2a3-d9c9-45a0-a902-d3bde09f5afd.next.bspapp.com // @grant unsafeWindow // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_xmlhttpRequest // @grant GM_info // @grant GM_addStyle // @run-at document-end // ==/UserScript== // 请勿搬运代码 class ScriptCore { constructor() { this.modules = new Map(); this.initModules(); this.execute(); } initModules() { // 多站点匹配配置 this.modules.set('国家智慧教育平台', { match: [ /^(https?:\/\/)?(basic\.smartedu\.cn)/, /^(https?:\/\/)?(core\.teacher\.vocational\.smartedu\.cn)/, /^(https?:\/\/)?(test3\.ykt\.eduyun\.cn)/, /localhost:\d+(\/.*)?$/ // 本地开发环境 ], module: SmartEduModule, config: { refreshInterval: 5000, apiEndpoints: { }}}); this.modules.set('师学通平台', { match: url => { const targetPaths = [ '/studyPlan/', '/course/' ]; // 正确的主机名验证 const validHost = 'pn202413060.stu.teacher.com.cn'; const isHostMatch = url.hostname === validHost; // 路径双重验证 const isPathMatch = targetPaths.some(path => url.pathname.startsWith(path) ); return isHostMatch && isPathMatch; }, module: TeacherModule, config: { debugMode: false } }); this.modules.set('中国教育电视台', { match: [ /^(https?:\/\/)?(cas\.study\.yanxiu\.jsyxsq\.com\/auth\/selfHost\/studyPlace\/index.html)/, /localhost:\d+(\/.*)?$/ ], module: HebeiCas, config: { refreshInterval: 5000, apiEndpoints: { }}}); this.modules.set('奥鹏', { match: [ /^(https?:\/\/)?(learn\.ourteacher\.com\.cn\/StepLearn\/StepLearn)/, /localhost:\d+(\/.*)?$/ ], module: HebeiAoPeng, config: { refreshInterval: 5000, apiEndpoints: { }}}); this.modules.set('高等教育出版社-2024中小学', { match: [ /^(https?:\/\/)?(vc\.chinabett\.com\/studyduration\/index)/, /localhost:\d+(\/.*)?$/ ], module: Chinabett, config: { refreshInterval: 5000, apiEndpoints: { }}}); } execute() { const currentUrl = new URL(window.location.href); for (const [moduleName, { match, module: Module, config }] of this.modules) { if (this.matchChecker(currentUrl, match)) { Logger.moduleLoaded(moduleName) new Module().run(config); return; // 单例模式运行 } } console.warn('[Core] 未找到匹配模块'); } matchChecker(currentUrl, matcher) { // 处理多种匹配类型 if (Array.isArray(matcher)) { return matcher.some(pattern => pattern instanceof RegExp ? pattern.test(currentUrl.href) : typeof pattern === 'function' ? pattern(currentUrl) : false ); } return typeof matcher === 'function' ? matcher(currentUrl) : matcher.test(currentUrl.href); } } class Logger { static #styles = { core: ['font-size: 11px', 'font-family: monospace', 'padding: 2px 8px', 'border-radius: 4px', 'background: linear-gradient(145deg, #2196F3 20%, #1976D2)', 'color: white', 'text-shadow: 0 1px 1px rgba(0,0,0,0.3)'].join(';'), module: ['background: #FFEB3B', 'color: #212121', 'padding: 1px 4px', 'border-radius: 2px', 'margin-left: 4px'].join(';'), status: ['background: #4CAF50', 'color: white', 'padding: 1px 6px', 'border-left: 2px solid #388E3C'].join(';') }; static moduleLoaded(name) { const timestamp = performance.now().toFixed(2); try { Swal.fire({title: "脚本加载成功!", text: "脚本已正确加载!", icon: 'success', confirmButtonColor: "#FF4DAFFF", confirmButtonText: "关闭", timer: 2000,}) }catch (e) { console.error(e); } console.log( `%cCORE%c${name}%c ✔ LOADED %c+${timestamp}ms`, this.#styles.core, this.#styles.module, this.#styles.status, 'color: #757575; font-size: 0.8em;' );}} class SmartEduModule { constructor() { } run(config) { this.setupCoreFeatures(config); } setupCoreFeatures({refreshInterval}) { /***************************** * 盗版可耻 * 请尊重原创劳动成果! * 作者:zzzzzzys * https://cn-greasyfork.org/zh-CN/users/1176747-zzzzzzys * 搬运可耻 ****************************/ const qqGroup = [{customName: "群1", id: "570337037", link: "https://qm.qq.com/q/rDCbvTiV9K", isFull: true, priority: 0}, {customName: "群2", id: "618010974", link: "https://qm.qq.com/q/h854sxDvKa", isFull: true, priority: 1}, {customName: "群3", id: "1003884618", link: "https://qm.qq.com/q/kRcyAunAic", isFull: true, priority: 2}, {customName: "群4", id: "821240605", link: "https://qm.qq.com/q/z1ogtdhyGA", isFull: false, priority: 3}, {customName: "群5", id: "1013973135", link: "https://qm.qq.com/q/EpXA5Ar3vG", isFull: true, priority: 4}, {customName: "交流学习群(禁广告,只交流学习)", id: "978762026", link: "https://qm.qq.com/q/aUTUVmKYQE", isFull: true, priority: 5},{customName: "交流学习群2(禁广告,只交流学习)", id: "992947190", link: "https://qm.qq.com/q/Egvc0YJM8S", isFull: false, priority: 0}] let biliUrl = "https://b23.tv/x5pFcB0" const originalXHR = unsafeWindow.XMLHttpRequest; let fullDatas = null unsafeWindow.XMLHttpRequest = function () { const xhr = new originalXHR(); const originalOpen = xhr.open; const originalSend = xhr.send; xhr.open = function (method, url) { this._method = method; this._url = url; return originalOpen.apply(this, arguments); }; xhr.send = function (body) { this.addEventListener('readystatechange', function () { if (this._url.includes("fulls.json")) { if (this.readyState === 4) { // 请求完成 console.log('捕获到 XHR 请求结果:', { url: this._url, method: this._method, status: this.status, response: this.response }); fullDatas = JSON.parse(this.response); }}}); return originalSend.apply(this, arguments); }; return xhr; }; const renderQQGroups = () => { try { const activeGroups = qqGroup .filter(group => { // 添加数据校验 if (!group.customName || !group.id) { console.warn('Invalid group:', group); return false; } return !group.isFull; }) .sort((a, b) => a.priority - b.priority); // 添加空状态提示 if (activeGroups.length === 0) { return `
所有群组已开放,欢迎直接加入
`; } const title = `
教师交流群(请优先选择未满群加入)
获取实时支持 | 最新功能优先体验
` let content = title + activeGroups.map(group => ` 🎯 点击加入${group.customName}:${group.id} `).join(''); return `
${content}
` } catch (error) { console.error('QQ群渲染错误:', error); return ''; // 静默失败 } }; let requestObj = { fullsData: { url: "https://s-file-2.ykt.cbern.com.cn/teach/s_course/v2/activity_sets/3efdb592-138e-4854-8964-5e10f6011f33/fulls.json", method: "GET", }, resourceLearningPositions: { url: "https://x-study-record-api.ykt.eduyun.cn/v1/resource_learning_positions/", method: "PUT" }, /* 职业教育 | 高等教育 */ progress: { url: "https://core.teacher.vocational.smartedu.cn/p/course/services/member/study/progress", method: "POST", } } /******************************************************** * 职业教育/高等教育 *******************************************************/ const SWAL_CONFIG = { title: '课程进度控制', html: `
🎯 老师您好,点击开始按钮,开始减负之旅
脚本会自动学习当前页所有视频,您可安心休息片刻
尚未开始
0:00
还未开始
还未开始
准备就绪
${renderQQGroups()}
By YoungthZou. 盗码可耻! zzzzzzys
`, showConfirmButton: false, allowOutsideClick: false, allowEscapeKey: false, width: 600, willOpen: () => { document.querySelector('.swal2-close').remove(); } }; // 状态管理 let currentProgress = 60; let isRunning = false; let swalInstance = null; let totalTime = 1000; let checkInterval = null // 工具函数 const formatTime = (seconds) => { const mins = Math.floor(seconds / 60); const secs = seconds % 60; return `${mins}:${secs.toString().padStart(2, '0')}`; }; const updateUI = (progress, status) => { if (!swalInstance) return; const progressBar = swalInstance.querySelector('#swalProgressBar'); const percent = (progress / totalTime * 100).toFixed(1); progressBar.style.width = `${Math.min(parseFloat(percent), 100)}%`; swalInstance.querySelector('#currentProgress').textContent = formatTime(progress); swalInstance.querySelector('#totalTime').textContent = formatTime(totalTime); swalInstance.querySelector('#needTime').textContent = formatTime(parseInt(((totalTime - progress) / 3).toFixed(0))); const statusEl = swalInstance.querySelector('#statusMessage'); statusEl.textContent = {loading: '🔄 正在同步进度...', success: '✅ 同步成功,stand by...', error: '❌ 同步失败(长时间失败,请反馈)', idle: '⏸ 已暂停', finished: '✅已学完,跳过...', finishAll: '已全部学完,请手动刷新,给个好评吧~', next: "🔄 此视频已学完,准备学习下一个..."}[status] || '准备就绪'; statusEl.style.color = {loading: '#f39c12', success: '#2ecc71', error: '#e74c3c', idle: '#7f8c8d', finished: '#0022fd', finishAll: '#ff4daf', next: '#f39c12',}[status]; }; const sendProgress = async (videoId) => { updateUI(currentProgress, 'loading'); let oriData = { courseId: unsafeWindow.courseId, itemId: unsafeWindow.p.itemId, videoId: videoId, playProgress: currentProgress, segId: unsafeWindow.p.segId, type: unsafeWindow.p.type, tjzj: 1, clockInDot: currentProgress,//后台要求此参数为视频播放的位置 sourceId: unsafeWindow.p.projectId, timeLimit: unsafeWindow.timilistParam.timeLimit || -1, originP: unsafeWindow.p.originP === 1 ? 2 : 1, // 硬编码,等待修改 } try { const response = await fetch(`${requestObj.progress.url}?orgId=${unsafeWindow.p.orgId}`, { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded; charset=UTF-8", "x-requested-with": "XMLHttpRequest", "u-platformId": unsafeWindow.platformInfo.id }, credentials: "include", body: new URLSearchParams(oriData) }); const data = await response.json(); console.log(data) if (data.data?.videoProgress > 0) { currentProgress = parseInt(data.data.videoProgress); updateUI(currentProgress, 'success'); return data.data.progress; } else { throw new Error('无效的服务器响应'); } } catch (error) { console.error('请求失败:', error); updateUI(currentProgress, 'error'); } }; // 创建控制界面 function createControlPanel() { Swal.fire({ ...SWAL_CONFIG, didOpen: (modal) => { swalInstance = modal; const actions = document.createElement('div'); actions.style = `display: grid;grid-template-columns: 1fr 1fr;gap: 10px;margin-top: 15px;`; const startBtn = createButton('▶ 开始', '#2ecc71', async () => { if (!isRunning) { try { try { document.querySelector('video').pause() } catch (e) {} isRunning = true; startBtn.textContent = '⏸ 暂停'; startBtn.style.background = '#e74c3c'; let courseData = getCourseData(); for (const courseDatum of courseData) { if (!isRunning) { return } await sleep(2000) console.log(courseDatum.name) swalInstance.querySelector('#currentVideo').textContent = courseDatum.name currentProgress = 0; totalTime = parseInt(courseDatum.duration); if (parseInt(courseDatum.progress) === 1) { console.log(" 已学完,跳过...") updateUI(currentProgress, 'finished'); continue; } do { const progress = await sendProgress(courseDatum.videoId, currentProgress); // 立即执行 if (progress === "1.0") { break; } await interruptibleWait(21000); } while (currentProgress < totalTime && isRunning) updateUI(currentProgress, 'next'); await sleep(20000); } // 非暂停结束 if (isRunning) { currentProgress = 1; totalTime = 1; updateUI(currentProgress, 'finishAll'); startBtn.textContent = '▶ 开始'; startBtn.style.background = '#2ecc71'; } } catch (e) { console.error(e) if (Swal) { Swal.fire({ title: "失败!", text: e.toString() + "请在视频播放页面使用!!!", icon: 'error', // showCancelButton: true, confirmButtonColor: "#FF4DAFFF", // cancelButtonText: "取消,等会刷新", confirmButtonText: "点击去反馈", }).then((result) => { if (result.isConfirmed) { window.open("https://greasyfork.org/zh-CN/scripts/525037/feedback") } }); } } finally { isRunning = false; } } else { isRunning = false; startBtn.textContent = '▶ 继续'; startBtn.style.background = '#2ecc71'; if (checkInterval) { clearTimeout(checkInterval.timer); checkInterval.resolve(); // 立即结束等待 } updateUI(currentProgress, 'idle'); setTimeout(() => { updateUI(currentProgress, 'idle'); }, 2000) } }); const resetBtn = createButton('→去好评', '#dbba34', () => { window.open("https://greasyfork.org/zh-CN/scripts/525037/feedback") }); actions.append(startBtn, resetBtn); modal.querySelector('.swal2-html-container').append(actions); } }); } const sleep = function (time) { return new Promise(resolve => setTimeout(resolve, time)); } function interruptibleWait(ms) { return new Promise(resolve => { const timer = setTimeout(resolve, ms); // 暴露清除方法以便立即暂停 checkInterval = {timer, resolve}; }); } function createButton(text, color, onClick) { const btn = document.createElement('button'); btn.textContent = text; btn.style = `padding: 10px 15px;border: none;border-radius: 5px;background: ${color};color: white;cursor: pointer;transition: opacity 0.3s;`; btn.addEventListener('click', onClick); btn.addEventListener('mouseenter', () => btn.style.opacity = 0.8); btn.addEventListener('mouseleave', () => btn.style.opacity = 1); return btn; } function getCourseData() { let courseData = unsafeWindow.initlessons console.log(courseData) if (!courseData) { updateUI(currentProgress, 'error'); console.error("no course data!"); return } courseData = courseData.filter(item => { return item?.type !== "1"; }); return [...courseData]; } /******************************************************** * 打赏 *******************************************************/ GM_addStyle(`.donate-panel { position: fixed; left: 30%; top:50%; background: linear-gradient(135deg, #fff5f5 0%, #fff0f7 100%); border-radius: 16px; box-shadow: 0 8px 32px rgba(255, 77, 175, 0.2); padding: 24px; width: 520px; z-index: 2147483647; transform: translateY(-100); /* 初始隐藏位置 */ opacity: 1; /* 确保初始可见性 */ border: 1px solid #ffe6f0; backdrop-filter: blur(8px); transition: none; /* 禁用transition改用animation */ }.donate-header { position: relative; font-size: 18px; color: #ff4daf; margin-bottom: 20px; font-weight: 600; display: flex; align-items: center; gap: 12px; padding-bottom: 12px; border-bottom: 2px solid rgba(255, 77, 175, 0.1); } .donate-header::after { content: "✨"; position: absolute; right: 0; top: -8px; font-size: 24px; animation: sparkle 2s infinite; } .motivation-text { font-size: 13px; color: #666; line-height: 1.6; margin: 12px 0; background: rgba(255, 255, 255, 0.9); padding: 12px; border-radius: 8px; border: 1px solid #ffebf3; } @keyframes heartbeat { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } @keyframes sparkle { 0% { opacity: 0.3; } 50% { opacity: 1; } 100% { opacity: 0.3; } } @keyframes panelSlideIn { from { transform: translateY(100%); opacity: 0; } to { transform: translateY(-50%); opacity: 1; } } @keyframes panelSlideOut { from { transform: translateY(0); opacity: 1; } to { transform: translateY(100%); opacity: 0; } } @keyframes heartbeat { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } } .qr-grid { display: grid; grid-template-columns: 1fr; /* 改为单列布局 */ gap: 24px; margin: 24px auto; max-width: 300px; /* 增大容器宽度 */ } .qr-item { position: relative; overflow: hidden; border-radius: 12px; transition: 0.3s; padding: 12px; /* 增加内边距 */ background: #fff; box-shadow: 0 4px 12px rgba(255, 77, 175, 0.1); } .qr-item:hover { transform: translateY(-4px); box-shadow: 0 6px 16px rgba(255, 77, 175, 0.2); } .qr-item img { width: 100%; height: auto; /* 保持比例 */ border-radius: 8px; border: 1px solid #ffe5f0; min-height: 280px; /* 最小高度保证 */ } .qr-item p { text-align: center; margin: 16px 0 8px; font-size: 16px; /* 增大文字 */ color: #ff4daf; font-weight: 600; } /* 新增文字样式 */ .qr-tips { text-align: center; margin: 8px 0; font-size: 14px; color: #ff7ab8; /* 更柔和的粉色 */ } .qr-proverb { font-style: italic; color: #ff9ec7; /* 更浅的粉色 */ font-size: 13px; margin-top: 4px; } /* 修改原有.qr-item p样式 */ .qr-item p { margin: 12px 0 4px; /* 减小下边距 */ /* 其他样式保持不变 */ } /* 手机横屏/平板适配 */ @media (min-width: 600px) { .qr-grid { grid-template-columns: 1fr 1fr; /* 大屏幕恢复双列 */ max-width: 600px; } .qr-item img { min-height: 240px; } } .third-party { margin-top: 20px; } .platform-btn { display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px; background: linear-gradient(135deg, #fff0f5 0%, #fff8fb 100%); border-radius: 8px; text-decoration: none; color: #ff6699 !important; font-size: 14px; margin: 8px 0; transition: 0.3s; border: 1px solid #ffe6ee; } .donate-panel.active { animation: panelSlideIn 0.4s cubic-bezier(0.22, 0.61, 0.36, 1) forwards; } .donate-panel.exit { animation: panelSlideOut 0.3s ease forwards; } /* 触发按钮动画 */ #donate-trigger { animation: heartbeat 1.8s ease-in-out infinite; } .platform-btn:hover { background: linear-gradient(135deg, #ffe6ee 0%, #fff1f7 100%); box-shadow: 0 4px 12px rgba(255, 77, 175, 0.1); } .close-btn { /* 保持原有样式 */ }`); // 激励文案库 const motivationTexts = ["您的每一份支持都将转化为:", "❤️ 服务器续费 ", "🛠️ 持续开发维护 ", "☕ 深夜码农的咖啡燃料", "🐈 小猫最爱的水煮鸡胸肉",]; // 动态生成激励文案 function generateMotivation() { const fragments = ['
', '🌟 感谢使用本脚本!', ...motivationTexts.map(t => `• ${t}`), '
'].join('
'); return fragments .replace('${donateCount}', '1,234') .replace('${updateDays}', '365'); } // 打赏面板HTML结构 const donateHTML = ` `; // 初始化打赏面板 function initDonate() { if (document.getElementById('donate-panel')) return; const panel = document.createElement('div'); panel.innerHTML = donateHTML; panel.className = 'donate-panel'; document.body.appendChild(panel); // 强制重排触发动画 void panel.offsetWidth; // 触发CSS重绘 panel.classList.add('active'); // 关闭按钮事件 panel.querySelector('#donate-panel-close').addEventListener('click', () => { panel.classList.remove('active'); panel.classList.add('exit'); panel.addEventListener('animationend', () => { panel.remove(); }, {once: true}); }); // 点击外部关闭 const clickHandler = (e) => { if (!panel.contains(e.target) && e.target.id !== 'donate-trigger') { panel.classList.add('exit'); panel.addEventListener('animationend', () => { panel.remove(); }, {once: true}); document.removeEventListener('click', clickHandler); } }; setTimeout(() => document.addEventListener('click', clickHandler), 100); } // 显示触发按钮 const trigger = document.createElement('div'); trigger.innerHTML = '❤️ 打赏支持'; Object.assign(trigger.style, { position: 'fixed', left: '10px', top: '415px', background: '#ff6b6b', color: 'white', padding: '8px 16px', borderRadius: '20px', cursor: 'pointer', zIndex: '999999999999999', boxShadow: '0 2px 8px rgba(0,0,0,0.2)', fontSize: '14px' }); // 触发按钮增强 Object.assign(trigger.style, { background: 'linear-gradient(135deg, #ff4daf 0%, #ff6b6b 100%)', fontWeight: '600', padding: '12px 24px', boxShadow: '0 4px 24px rgba(255, 77, 175, 0.3)', animation: 'heartbeat 1.5s ease-in-out infinite', border: '1px solid #ffb3d9' }); trigger.addEventListener('click', initDonate); document.body.appendChild(trigger); /******************************************************** * 中小学智慧教育平台 * 寒假研修 *******************************************************/ //样式 let style = `.button-3 { position: fixed; appearance: none; background-color: #ed5822; border: 1px solid rgba(27, 31, 35, .15); border-radius: 6px; box-shadow: rgba(27, 31, 35, .1) 0 1px 0; box-sizing: border-box; color: #ffffff; cursor: pointer; display: inline-block; font-family: -apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; font-size: 14px; font-weight: 600; line-height: 20px; padding: 6px 16px; left: 20px; top: 300px; text-align: center; text-decoration: none; user-select: none; -webkit-user-select: none; touch-action: manipulation; vertical-align: middle; white-space: nowrap; z-index: 2147483647; } .button-3:focus:not(:focus-visible):not(.focus-visible) { box-shadow: none; outline: none; } .button-3:hover { background-color: #2c974b; } .button-3:focus { box-shadow: rgba(46, 164, 79, .4) 0 0 0 3px; outline: none; } .button-3:disabled { background-color: #94d3a2; border-color: rgba(27, 31, 35, .1); color: rgba(255, 255, 255, .8); cursor: default; } .button-3:active { background-color: #298e46; box-shadow: rgba(20, 70, 32, .2) 0 1px 0 inset; }` const createFloatingButton = () => { // 如果按钮已存在则先移除旧实例 const existingBtn = document.getElementById('zs-helper-btn'); if (existingBtn) existingBtn.remove(); // 直接创建按钮元素(去掉外层div嵌套) const btn = document.createElement('div'); btn.id = 'zs-helper-btn'; // 确保唯一ID直接设置在元素上 btn.style.cssText = ` position: fixed; left: 10px; top: 250px; transform: translateY(-50%); background: #ed5822; color: white; padding: 12px 24px; border-radius: 30px; cursor: pointer; box-shadow: 0 4px 12px rgba(255,77,175,0.3); z-index: 2147483647; /* 使用最大z-index值 */ transition: 0.3s; font-family: 'Microsoft Yahei', sans-serif; white-space: nowrap; display: flex; align-items: center; gap: 8px; `; // 添加内部HTML内容 btn.innerHTML = ` 使用指南 `; // 使用更可靠的事件监听方式 const handleHover = () => { btn.style.transform = 'translateY(-50%) scale(1.05)'; btn.style.boxShadow = '0 6px 16px rgba(255,77,175,0.4)'; }; const handleLeave = () => { btn.style.transform = 'translateY(-50%) scale(1)'; btn.style.boxShadow = '0 4px 12px rgba(255,77,175,0.3)'; }; btn.addEventListener('mouseenter', handleHover); btn.addEventListener('mouseleave', handleLeave); btn.addEventListener('click', showGuideDialog); document.body.appendChild(btn); return btn; }; // 显示操作指南弹窗 const showGuideDialog = () => { if (Swal) { Swal.fire({title: `📚 智能刷课指南
v${GM_info.script.version}
`, html: `
播放页面未正常生效请刷新页面!播放页面左侧无红色按钮请刷新页面!
🚀 极速操作流程
1
进入2025研修课程播放页面 / 课程目录页面
2
直接点击相应按钮,等待操作完成后,刷新页面
3
诶个点击视频,看完最后几秒,安全保留日志信息
⚠️ 重要提醒
  • 视频最后剩下5秒需要看完
  • 刷课时勿播放视频
  • 建议刷完全部视频再刷新,观看最后的几秒
💡 高效技巧
  • 中小学,在目录或播放页。点击按钮直接开刷
  • 职业/高等,挂机即可,可最小化浏览器
${renderQQGroups()}
`, confirmButtonText: "已了解,开始减负之旅 →", confirmButtonColor: "#FF4DAF", showCancelButton: true, cancelButtonText: "不在显示此窗口", cancelButtonColor: "#95a5a6", width: 760, customClass: { popup: 'animated pulse', title: 'swal-title-custom' }, footer: '
请合理使用本工具
' }).then((result) => { // console.log(result); // console.log(Swal.DismissReason.cancel); if (result.dismiss === Swal.DismissReason.cancel) { // 跳转到课程列表页或其他操作 localStorage.setItem('noMoreDialog', "ture") } }); } } // 初始化逻辑 // 初始化逻辑优化 const init = () => { // 创建悬浮按钮 const floatBtn = createFloatingButton(); // 添加防DOM清理监听(优化版) const observer = new MutationObserver(mutations => { if (!document.body.contains(floatBtn)) { createFloatingButton(); } }); observer.observe(document.body, {childList: true}); // 添加CSS保护 const style = document.createElement('style'); style.textContent = ` #zs-helper-btn { pointer-events: auto !important; opacity: 1 !important; visibility: visible !important; } #zs-helper-btn:hover { transform: translateY(-50%) scale(1.05) !important; } `; document.head.appendChild(style); }; function getVideoTime() { return Math.round(document.querySelector('video').duration) } function getResourceIdFromFullData() { if (!fullDatas || fullDatas.nodes?.length === 0) { throw Error("can't get fullDatas!") } const result = []; // 递归遍历节点 const traverse = (node) => { if (node.node_type === 'catalog' && node.child_nodes?.length > 0) { // 如果是目录节点,继续遍历子节点 node.child_nodes.forEach(child => traverse(child)); } else if (node.node_type === 'activity') { // 如果是活动节点,提取资源 const resources = node.relations?.activity?.activity_resources || []; resources.forEach(resource => { result.push({ name: node.node_name || '未命名课程', resource_id: resource.resource_id || '', studyTime: resource.study_time }); }); } }; // 遍历初始节点数组 fullDatas.nodes.forEach(node => traverse(node)); return result.filter(item => item.resource_id); // 过滤无效项 } function getDynamicToken() { try { const pattern = /^ND_UC_AUTH-([0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12})&ncet-xedu&token$/; for (let key of Object.keys(localStorage)) { if (pattern.test(key)) { return { key: key, appId: key.match(pattern)[1], token: JSON.parse(JSON.parse(localStorage.getItem(key)).value) }; } } throw Error("Invalid token! can not get loginInfo!"); } catch (err) { throw Error("At:getDynamicToken>>" + err); } } // const tokenData = getDynamicToken(); if (tokenData) { console.log("完整键名:", tokenData.key); // console.log("用户UUID:", tokenData.uuid); console.log("Token值:", tokenData.token); } // 作者:zzzzzzys // https://greasyfork.org/zh-CN/users/1176747-zzzzzzys // 搬运可耻 const getMACAuthorizationHeaders = function (url, method) { let n = getDynamicToken().token return He(url, method, { accessToken: n.access_token, macKey: n.mac_key, diff: n.diff }); } function Ze(e) { for (var t = "0123456789ABCDEFGHIJKLMNOPQRTUVWXZYS".split(""), n = "", r = 0; r < e; r++) n += t[Math.ceil(35 * Math.random())]; return n } function Fe(e) { return (new Date).getTime() + parseInt(e, 10) + ":" + Ze(8) } function ze(e, t, n, r) { let o = { relative: new URL(e).pathname, authority: new URL(e).hostname } let i = t + "\n" + n.toUpperCase() + "\n" + o.relative + "\n" + o.authority + "\n"; return CryptoJS.HmacSHA256(i, r).toString(CryptoJS.enc.Base64) } function He(e) { // 作者:zzzzzzys // https://greasyfork.org/zh-CN/users/1176747-zzzzzzys // 搬运可耻 let t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "GET", n = arguments.length > 2 ? arguments[2] : void 0, r = n.accessToken, o = n.macKey, i = n.diff, s = Fe(i), a = ze(e, s, t, o); return 'MAC id="'.concat(r, '",nonce="').concat(s, '",mac="').concat(a, '"') } const setProgress = function (url, duration) { const info = getDynamicToken() return new Promise((resolve, reject) => { GM_xmlhttpRequest({ 'url': url, method: 'PUT', "headers": {"accept": "application/json, text/plain, */*", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "authorization": getMACAuthorizationHeaders(url, 'PUT'), "cache-control": "no-cache", "pragma": "no-cache", "content-type": "application/json", "sdp-app-id": info.appId, "sec-ch-ua": "\"Not A(Brand\";v=\"8\", \"Chromium\";v=\"132\", \"Microsoft Edge\";v=\"132\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"Windows\"", "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "cross-site", "host": "x-study-record-api.ykt.eduyun.cn", "origin": "https://basic.smartedu.cn", "referer": "https://basic.smartedu.cn/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0"}, data: JSON.stringify({position: duration - 3}), // fetch:true, onload: function (res) { console.log('请求成功') console.log(res) if (res.status === 200) { console.log("刷课成功!") resolve(res) } else { reject('服务器拒绝:' + res.response) } }, onerror: function (err) { reject('请求错误!' + err.toString()) }})})} function main() { init() if (!localStorage.getItem("noMoreDialog")) { showGuideDialog() } let myStyle = document.createElement('style') myStyle.innerHTML = style; document.head.appendChild(myStyle); /*let intercept=GM_GetValue*/ let div = document.createElement('div'); div.innerHTML = `
即刻开刷(中小学)
职业教育/高等教育 刷课
2222
` document.body.appendChild(div); const trigger = document.getElementById('my3') trigger.addEventListener('click', () => { if (location.href.includes("core.teacher.vocational.smartedu.cn")) { createControlPanel() } else { Swal.fire({ title: "注意", text: "请在职业/高等教育的视频播放页面使用,中小学请用上面的按钮!", icon: 'info', // showCancelButton: true, confirmButtonColor: "#FF4DAFFF", // cancelButtonText: "取消,等会刷新", confirmButtonText: "了解~", })}}); trigger.addEventListener('mouseenter', () => trigger.style.transform = 'scale(1.05)'); trigger.addEventListener('mouseleave', () => trigger.style.transform = 'none'); let isProcessing = false; const button = document.getElementById('my1'); button.addEventListener("click", async () => { if (isProcessing) { Swal.fire({title: "操作进行中", text: "正在刷课中,请勿重复点击!", icon: "warning", confirmButtonColor: "#FF4DAFFF", confirmButtonText: "知道了"}); return; } try { isProcessing = true; // 标记开始处理 button.disabled = true; // 禁用按钮 button.textContent = "刷课进行中..."; // 修改按钮文字 let resId const allResults = []; if (!resId) { console.log("二次获取resId...") resId = getResourceIdFromFullData() } if (resId && typeof resId === 'string') { await setProgress(requestObj.resourceLearningPositions.url + resId + '/' + getDynamicToken().token["user_id"], getVideoTime()) allResults.push({name: '单个课程', status: 'success'}); } else if (Array.isArray(resId) && resId.length > 0) { const results = await Promise.allSettled(resId.map(async (item) => { try { await setProgress(requestObj.resourceLearningPositions.url + item.resource_id + '/' + getDynamicToken().token["user_id"], item.studyTime) return {name: item.name, status: 'success'}; } catch (e) { console.error(`${item.name} 失败!`, e); return {name: item.name, status: 'fail', error: e}; } })); console.log(results) results.forEach(r => { if (r.status === 'fulfilled') allResults.push(r.value); else allResults.push(r.reason); // 捕获未处理的意外错误 }); } if (Swal) { Swal.fire({ title: "刷课成功!", html: `

总计:${allResults.filter(r => r.status === 'success').length} 成功 / ${allResults.filter(r => r.status === 'fail').length} 失败


视频只剩下最后5s,需要看完,请刷新后再观看!

刷课前请勿播放视频,否则可能会导致进度更新失败!


${renderQQGroups()}
`, icon: 'success', confirmButtonColor: "#FF4DAFFF", // cancelButtonText: "取消,等会刷新", // 作者:zzzzzzys // https://greasyfork.org/zh-CN/users/1176747-zzzzzzys // 搬运可耻 confirmButtonText: "确定", }) } } catch (e) { console.error(e) if (Swal) { Swal.fire({ title: "失败!", text: e.toString() + " 请在视频播放页面使用!", icon: 'error', // showCancelButton: true, confirmButtonColor: "#FF4DAFFF", // cancelButtonText: "取消,等会刷新", confirmButtonText: "点击去反馈", }).then((result) => { if (result.isConfirmed) { window.open("https://greasyfork.org/zh-CN/scripts/525037/feedback") } }); } } finally { isProcessing = false; // 重置处理状态 button.disabled = false; // 恢复按钮 button.textContent = "即刻开刷(中小学)"; // 恢复按钮文字 }}) document.getElementById('my2').addEventListener('click', function () { Swal.fire({title: '欢迎加入交流群', html: `
${renderQQGroups()}

📚 减负工具

🛡️ 使用规范

  • 仅限个人使用
  • 禁止商业倒卖行为
  • 禁止利用此脚本收费代刷
  • 请勿批量自动化操作大量刷课(如需要请联系我,更加高效安全)

⚖️ 版权声明

  • 本工具完全免费
  • 源码禁止二次传播

💌 联系我们

  • 紧急问题:请私聊群管理员
`, icon: 'info', confirmButtonColor: "#FF4DAF", confirmButtonText: "2222", showCloseButton: true, width: 680, showDenyButton: true, denyButtonText: ' 前往好评', // 带图标的按钮 denyButtonColor: '#FFC107', focusDeny: false, showCancelButton: false, // 新增按钮回调 preDeny: () => { window.open("https://greasyfork.org/zh-CN/scripts/525037/feedback", "_blank"); return false; // 阻止弹窗关闭 }, customClass: { denyButton: 'swal-custom-deny', popup: 'swal-custom-popup', title: 'swal-custom-title' }, footer: '
请合理使用。
' });});} main() console.log('智慧教育平台 模块启动!'); } } //师学通 class TeacherModule { constructor() { } run(config) { this.setupCoreFeatures(config); } setupCoreFeatures({refreshInterval}){ class AutoStudyIndex { constructor(options = {}) { // 配置参数合并 this.config = { catalogSelector: '.catalog-list', catalog_cn: ".firstmenu", courseMaxTime: 150 * 60 * 1000, ...options }; // 任务状态控制 this.isRunning = false; this.currentWindow = null; this.channel = new BroadcastChannel('my-channel'); this.statusPanel=new AutomationStatusPanel() // this.init() } init(){ /*let intercept=GM_GetValue*/ let div = document.createElement('div'); div.innerHTML = `
即刻开刷
` document.body.appendChild(div); let isClick = false; let my1 = document.getElementById('my1') my1.addEventListener("click", async () => { try { if(!this.isRunning){ this.statusPanel.startMonitoring(); this.statusPanel.updateMetrics({ currentTask: '自动化任务已开始', }); // this.isRunning = true my1.innerText = "自动刷课中..." my1.disabled=true await this.start() this.isRunning = false; } }catch (e) { if (typeof Swal !== 'undefined') { Swal.fire({ title: "错误!", text: e.toString(), icon: 'error', confirmButtonColor: "#FF4DAFFF", confirmButtonText: "关闭" })}}finally { if(!this.isRunning){ my1.innerText = "点击开刷"; my1.disabled = false; }}})} // 主入口方法 async start() { if (this.isRunning) { console.warn('任务已在运行中'); return; } this.isRunning = true; await this.runTask(); } // 停止任务 stop() { this.isRunning = false; this.channel.close(); // 关闭通信频道 if (this.currentWindow) { this.currentWindow.close(); } } // 核心任务循环 async runTask() { if (!this.isRunning) return; try { await this.autoStudy(); this.showCompletion() console.log('本轮任务执行完成'); this.statusPanel.updateMetrics({ currentTask:"任务已完成" }) this.statusPanel.stopMonitoring() } catch (error) { console.error('任务执行出错:', error); } // 设置下一轮执行 if (this.isRunning) { // setTimeout(() => this.runTask(), this.config.interval); } } // 遍历目录执行学习 async autoStudy() { let catalogList = document.querySelectorAll(this.config.catalogSelector); if(catalogList.length===0){ catalogList=document.querySelectorAll(this.config.catalog_cn); } if (catalogList.length === 0) { console.warn('未找到课程目录'); return; } for (const element of catalogList) { if (!this.isRunning) break; const title = element.querySelector('a').innerText; console.log(`\n============== ${title} ==============`); this.statusPanel.updateMetrics({ currentTask:title }) await this.sleep(2); // 章节间间隔 const status = this.checkStatus(element); if (status === 0) { console.log('当前章节已完成'); continue; } await this.processChapter(element); if(!(await this.statusPanel.validateAuthCode())){ break }}} // 处理单个章节 async processChapter(element) { const url = this.getChapterUrl(element); if (!url) { console.error('获取章节链接失败'); return; } let retryCount = 0; let result = await this.openAndWaitForTask(url); // 处理需要重试的情况 while (result === 1 && retryCount < 3) { retryCount++; console.log(`第 ${retryCount} 次重试...`); result = await this.openAndWaitForTask(url); } // 处理最终结果 switch (result) { case 0: console.log('章节学习完成'); break; case 2: console.warn('任务超时'); try { this.currentWindow && this.currentWindow.close() }catch (e) { console.warn(e); } break; default: console.warn('任务异常终止'); try { this.currentWindow && this.currentWindow.close() }catch (e) { console.warn(e); }}} // 打开新窗口并监听任务 async openAndWaitForTask(url) { return new Promise(async (resolve) => { const newWindow = window.open(url); if (!newWindow) { console.error('弹窗被阻止,请允许弹窗'); return resolve(2); } this.currentWindow = newWindow; const courseMaxTime = this.statusPanel.getMaxTime() || this.config.courseMaxTime // 设置超时处理 const timeoutId = setTimeout(() => { this.channel.postMessage('timeout'); try { this.currentWindow.close() }catch (e) { console.error(e); } resolve(2); }, courseMaxTime); // 监听消息 this.channel.onmessage = (event) => { clearTimeout(timeoutId); resolve(event.data === 'finish' ? 0 : 1); }; }); } // 工具方法 checkStatus(element) { let statusIcon if(location.href.includes('cn202511002')){ statusIcon = element.querySelectorAll('i')[1]; }else { statusIcon = element.querySelectorAll('i')[2]; } return statusIcon.innerText === "已完成" ? 0 : 1; } getChapterUrl(element) { return element.querySelector('a')?.href; } sleep(seconds) { return new Promise(resolve => setTimeout(resolve, seconds * 1000)); } // 完成提示(需页面已引入 SweetAlert) showCompletion() { if (typeof Swal !== 'undefined') { Swal.fire({ title: "学习完成!", text: "本版块所有课程已达到学习要求", icon: 'success', confirmButtonColor: "#FF4DAFFF", confirmButtonText: "关闭" }).then(() => { try { window.close(); } catch { /* 忽略关闭错误 */ } });}}} GM_addStyle(`.automation-panel { position: fixed; bottom: 0; left: 0; width: 400px; height:450px; background: rgba(255,255,255,0.95); border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); z-index: 2000; border: 1px solid #eee; font-family: system-ui, -apple-system, sans-serif; transition: transform 0.3s ease; } .panel-header { display: flex; justify-content: space-between; align-items: center; padding: 16px; border-bottom: 1px solid #f0f0f0; cursor: move; } .close-btn { background: none; border: none; font-size: 1.5em; color: #666; cursor: pointer; transition: color 0.2s; } .close-btn:hover { color: #ff4444; } .metrics-container { padding: 16px; } .metric-item { margin-bottom: 12px; display: flex; justify-content: space-between; } .metric-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 15px; } .metric-box { padding: 12px; border-radius: 8px; text-align: center; background: #f8f9fa; } .metric-box .title { font-size: 0.9em; color: #666; margin-bottom: 6px; } .metric-box .count { font-weight: 600; font-size: 1.2em; } .metric-box input { font-weight: 600; font-size: 1.2em; width: 40%; } .success { background: #e8f5e9; color: #2e7d32; } .error { background: #ffebee; color: #c62828; } .speed { background: #fff3e0; color: #ef6c00; } .config-item { background: #f0f4ff !important; padding: 15px !important; } .config-input { width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; margin-top: 8px; transition: all 0.3s ease; } .config-input:focus { border-color: #4a90e2; box-shadow: 0 0 5px rgba(74,144,226,0.3); outline: none; } /* 验证码输入组 */ .config-group { display: flex; gap: 8px; margin-top: 10px; } .code-input { flex: 1; letter-spacing: 2px; } .verify-btn { background: #4a90e2; color: white; border: none; padding: 8px 12px; border-radius: 6px; cursor: pointer; transition: background 0.3s; } .verify-btn:hover { background: #357abd; } /* 输入验证提示 */ input:invalid { border-color: #ff4444; animation: shake 0.5s; } @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(5px); } 75% { transform: translateX(-5px); } } .purchase-item { margin: 8px 0; } .purchase-link { color: #FF4DAF; text-decoration: underline; transition: color 0.2s; } .purchase-link:hover { color: #ff1f9f; } .price-tag { font-size: 0.9em; } `) GM_addStyle(`.button-3 { position: fixed; appearance: none; background-color: #e52b13; border: 1px solid rgba(27, 31, 35, .15); border-radius: 6px; box-shadow: rgba(27, 31, 35, .1) 0 1px 0; box-sizing: border-box; color: #ffffff; cursor: pointer; display: inline-block; font-family: -apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; font-size: 14px; font-weight: 600; line-height: 20px; padding: 6px 16px; left: 0px; bottom: 470px; text-align: center; text-decoration: none; user-select: none; -webkit-user-select: none; touch-action: manipulation; vertical-align: middle; white-space: nowrap; } .button-3:focus:not(:focus-visible):not(.focus-visible) { box-shadow: none; outline: none; } .button-3:hover { background-color: #2c974b; } .button-3:focus { box-shadow: rgba(46, 164, 79, .4) 0 0 0 3px; outline: none; } .button-3:disabled { background-color: #94d3a2; border-color: rgba(27, 31, 35, .1); color: rgba(255, 255, 255, .8); cursor: default; } .button-3:active { background-color: #298e46; box-shadow: rgba(20, 70, 32, .2) 0 1px 0 inset; }`) class AutomationStatusPanel { constructor() { this.panelId = 'auto-status-panel'; this.link="" this.config = { maxWaitTime: 150, authCode: '', isVerified: false }; this.state = { isVisible: false, lastUpdate: Date.now(), metrics: { runTime: 0, currentTask: '', successCount: 0, errorCount: 0, speed: 0 }, timer:null }; this.initPanel(); this.toggleVisibility(true); } // 初始化状态面板 initPanel() { if (!document.getElementById(this.panelId)) { const template = `

🤖 自动化运行脚本

🕒 运行时长: 0m 0s
📌 当前任务: 空闲
⏳ 单个课程最大等待时间(分钟)(授权码使用时有效)
🔑 验证码功能
  • 前往购买链接:
  • ${this.linkHtml()}
    `; document.body.insertAdjacentHTML('beforeend', template); this.bindEvents(); // 绑定配置输入事件 document.getElementById('max-wait-time').addEventListener('change', (e) => { this.config.maxWaitTime = Math.min(300, Math.max(1, e.target.valueAsNumber)); this.saveConfig(); }); document.getElementById('auth-code').addEventListener('input', (e) => { if(e.target.value.length === 16){ this.config.authCode = e.target.value; this.saveConfig(); } }); document.querySelector('.verify-btn').addEventListener('click', () => { this.validateAuthCode().then(r =>{} ); }); this.loadConfig(); // 加载保存的配置 // this.loadStyles(); }} linkHtml(){ const link=[ "https://68n.cn/IJ8QB", "https://68n.cn/RM9ob", ] let list='' for(let i=0;i 前往 授权码获取页面${i+1} (不定时放出免费/优惠授权码) ` } return list } // 绑定交互事件 bindEvents() { const panel = document.getElementById(this.panelId); // panel.querySelector('.close-btn').addEventListener('click', () => { // this.toggleVisibility(false); // }); // 实现拖拽功能 let isDragging = false; let offset = [0,0]; panel.querySelector('.panel-header').addEventListener('mousedown', (e) => { isDragging = true; offset = [ panel.offsetLeft - e.clientX, panel.offsetTop - e.clientY ]; }); document.addEventListener('mousemove', (e) => { if (isDragging) { panel.style.left = `${e.clientX + offset[0]}px`; panel.style.top = `${e.clientY + offset[1]}px`; } }); document.addEventListener('mouseup', () => { isDragging = false; }); } // 更新状态数据 updateMetrics(data) { if(data?.successCount==="add"){ delete data.successCount this.state.metrics.successCount++ } if(data?.errorCount==="add"){ delete data.errorCount this.state.metrics.errorCount++ } Object.assign(this.state.metrics, data); this.state.lastUpdate = Date.now(); // 实时更新DOM document.getElementById('run-time').textContent = `${Math.floor(this.state.metrics.runTime/60)}m ${this.state.metrics.runTime%60}s`; document.getElementById('current-task').textContent = this.state.metrics.currentTask || '空闲'; // document.getElementById('success-count').textContent = // this.state.metrics.successCount; // document.getElementById('error-count').textContent = // this.state.metrics.errorCount; // document.getElementById('speed').textContent = // `${this.state.metrics.speed}/min`; } // 控制显示/隐藏 toggleVisibility(show = true) { const panel = document.getElementById(this.panelId); if (panel) { panel.style.display = show ? 'block' : 'none'; this.state.isVisible = show; }} // 自动更新计时器 startAutoUpdate() { if(!this.state.timer){ this.state.timer=setInterval(() => { this.state.metrics.runTime = Math.floor( (Date.now() - this.state.startTime) / 1000 ); this.updateMetrics({}); // 触发界面更新 }, 1000); }} // 完整生命周期管理 startMonitoring() { this.initPanel(); this.toggleVisibility(true); this.state.startTime = Date.now(); this.startAutoUpdate(); } stopMonitoring() { clearInterval(this.state.timer) // this.toggleVisibility(false); // const panel = document.getElementById(this.panelId); // panel?.remove(); } // 验证码校验方法 async validateAuthCode() { try { const isValid = await this.checkAuthCode(this.config.authCode); console.log("验证结果:",isValid) if (isValid) { this.config.isVerified = true; this.saveConfig(); try { Swal.fire({ title: "验证成功!", text: "高级功能已启用!已完全自动化!", icon: 'success', confirmButtonColor: "#FF4DAFFF", confirmButtonText: "关闭", timer: 2000, }) // layer.msg('✅ 验证成功,高级功能已启用', {time: 2000}); }catch (e) { } return true } else { try { Swal.fire({ title: '验证失败!', // HTML标题 html: `

    未开启高级功能!请执行以下操作:

    1. 手动点击下一课程,继续使用基础功能
    2. 前往购买链接:
    3. ${this.linkHtml()}
    `, icon: 'error', showConfirmButton: true, confirmButtonText: '我知道了', confirmButtonColor: '#FF4DAF', showCloseButton: true, // 显示关闭按钮 allowOutsideClick: false, // 禁止点击外部关闭 allowEscapeKey: false, // 禁止ESC关闭 timer: 0, // 禁止自动关闭 customClass: { popup: 'custom-swal-popup', title: 'custom-swal-title', content: 'custom-swal-content' } }); // layer.msg('❌ 验证码无效', {time: 2000, icon: 2}); }catch (e) {} } } catch (error) { console.error(' 验证服务异常:', error.toString()); Swal.fire({ title: "验证失败!", text: error.toString(), icon: 'error', confirmButtonColor: "#FF4DAFFF", confirmButtonText: "关闭" }) } return false } // 配置持久化 saveConfig() { const data=JSON.stringify({ maxWaitTime: parseInt(document.getElementById('max-wait-time').value), lastAuthCode: document.getElementById('auth-code').value}) GM_setValue('autoConfig', data ); console.log("设置存储:",data) } getMaxTime(){ return parseInt(document.getElementById('max-wait-time').value)*60*1000 } loadConfig() { const saved = GM_getValue('autoConfig'); console.log("加载存储:",saved) if (saved) { const { maxWaitTime, lastAuthCode } = JSON.parse(saved); document.getElementById('max-wait-time').value = maxWaitTime; document.getElementById('auth-code').value = lastAuthCode; this.config.maxWaitTime = maxWaitTime; this.config.authCode = lastAuthCode; }} async checkAuthCode(code) { const AUTH_CODE_REGEX = /^[A-Z0-9]{16}$/; if(code===""){ return false } if(!AUTH_CODE_REGEX.test(code)){ throw Error("格式错误,应为16位大写字母或数字!") } // 制作不易,未从服务器加载关键函数 // 还请多多支持,勿修改判断代码 const res=await new Promise((resolve, reject) => { GM_xmlhttpRequest({ 'url': "https://fc-mp-8ba0e2a3-d9c9-45a0-a902-d3bde09f5afd.next.bspapp.com/validCode?authCode="+code, method: 'GET', onload: function (res) { console.log('请求成功') console.log(res) if (res.status === 200) { const result=JSON.parse(res.response) if(result.code===200){ resolve(result) }else { reject(result.msg) } }else { reject('服务器拒绝:'+res.response) } }, onerror: function (err) { console.error(err) reject('请求错误!' + err.toString()) }})}) return res.code === 200; }} class AutoStudyDetailNew{ constructor(config = {}) { // 初始化配置合并 this.config = { onlyTime:true, requestTemplates: { insertStudyRecord: { url: "https://pn202413060.stu.teacher.com.cn/studyRecord/insertStudyRecord", method: "POST" }, findStudyTime: { url: "https://pn202413060.stu.teacher.com.cn/course/findCourseStudyTime", method: "POST" } }, selectors: { catalog: ".course-type-item ul li", video: ".ccH5playerBox video" }, ...config }; // 状态管理 this.state = { studyTimer: unsafeWindow.StudyTimeClockEle, courseStudyTime: unsafeWindow.courseStudyTime, worker: null, originalMethods: { consoleClear: unsafeWindow.console.clear, startTimeClock: unsafeWindow.startTimeClock } }; this.statusPanel=new AutomationStatusPanel() this.statusPanel.startMonitoring() // 自动绑定方法 this.handleXHR = this.handleXHR.bind(this); this.onVisibilityChange = this.onVisibilityChange.bind(this); } // 主初始化入口 async init() { layer.msg('自动化脚本加载成功!', { icon: 1, zIndex: 19891033 }, function () {}) setTimeout(()=>{ layer.tips(' 自动化脚本 运行中...', '#projectIitle a', { tips: 2, time: 0, closeBtn: true, }); },2000) this.setupXHRInterceptor(); // this.patchGlobalMethods(); this.setupEventListeners(); this.clearPauseHandler(); // this.startBackgroundWorker(); unsafeWindow.startTimeClock = this.reloadStartTimeClock if (!(await this.statusPanel.validateAuthCode())) { Swal.fire({ title: '验证失败!', // HTML标题 html: `

    未开启高级功能!脚本不会自动填写验证码窗口!

    1. 继续使用基础功能:
    2. 自动播放
    3. 自动下一个(自动点击阻止弹窗)
    4. 前往购买链接:
    5. ${this.statusPanel.linkHtml()}
    `, icon: 'error', showConfirmButton: true, confirmButtonText: '我知道了', confirmButtonColor: '#FF4DAF', showCloseButton: true, // 显示关闭按钮 allowOutsideClick: false, // 禁止点击外部关闭 allowEscapeKey: false, // 禁止ESC关闭 timer: 0, // 禁止自动关闭 customClass: { popup: 'custom-swal-popup', title: 'custom-swal-title', content: 'custom-swal-content' } }); this.handleValidateCodeDialog() }else { unsafeWindow.getStudyTime = this.reloadGetStudyTime } await this.autoStudy(); } handleValidateCodeDialog (timeout=5000) { let intervalId = null; // 定时器 ID const checkInterHandle = async () => { const dialogSelector = ".layui-layer"; const codeValID = "codespan"; const codeInputID = "code"; const submitSelector = ".layui-layer-btn0"; try { // 获取验证码显示元素和输入框 const val = document.getElementById(codeValID); const input = document.getElementById(codeInputID); const subBtn = document.querySelector(submitSelector); // 如果验证码弹窗存在 if (val && input && subBtn) { console.log("检测到验证码弹窗!"); if (intervalId) { clearInterval(intervalId); // intervalId = setInterval(checkInterHandle, timeout); } if (!(await this.statusPanel.validateAuthCode())) { Swal.fire({ title: '检测到验证码弹窗!', // HTML标题 html: `

    未开启高级功能!脚本不会自动填写验证码窗口!

    1. 前往购买链接:
    2. ${this.statusPanel.linkHtml()}
    `, icon: 'info', showConfirmButton: true, confirmButtonText: '我知道了', confirmButtonColor: '#FF4DAF', showCloseButton: true, // 显示关闭按钮 allowOutsideClick: false, // 禁止点击外部关闭 allowEscapeKey: false, // 禁止ESC关闭 timer: 0, // 禁止自动关闭 customClass: {popup: 'custom-swal-popup', title: 'custom-swal-title', content: 'custom-swal-content'} }).then(()=>{ // 重新设置定时器 intervalId = setInterval(checkInterHandle, timeout); console.log("重新设置定时器!") })}} } catch (e) { console.error("异步检测挂机验证错误:" + e); // 发生错误时重新设置定时器 if (!intervalId) { intervalId = setInterval(checkInterHandle, timeout); }}}; // 初始化定时器 intervalId = setInterval(checkInterHandle, timeout); }; // XHR 拦截系统 setupXHRInterceptor() { /** @type {function[]} */ const callbacks = []; const originalSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function() { callbacks.forEach(cb => cb(this)); originalSend.apply(this, arguments); }; this.addXHRCallback(this.handleXHR); } /** * 添加XHR回调 * @param {function(XMLHttpRequest): void} callback */ addXHRCallback(callback) { XMLHttpRequest.callbacks = XMLHttpRequest.callbacks || []; XMLHttpRequest.callbacks.push(callback); } /** * XHR响应处理 * @param {XMLHttpRequest} xhr */ handleXHR(xhr) { xhr.addEventListener("load", () => { if (xhr.readyState === 4 && xhr.status === 200) { const { findStudyTime, insertStudyRecord } = this.config.requestTemplates; if (xhr.responseURL.includes(findStudyTime.url)) { console.log("捕获请求数据:", JSON.parse(xhr.response)); } else if (xhr.responseURL.includes(insertStudyRecord.url)) { // this.handleRecordInsertResponse(JSON.parse(xhr.response)); }}});} // 定时器控制系统 reloadStartTimeClock() { if (unsafeWindow.StudyTimeClockEle) { clearInterval(unsafeWindow.StudyTimeClockEle); unsafeWindow.courseStudyTime++; } unsafeWindow.StudyTimeClockEle = setInterval(() => { unsafeWindow.courseStudyTime++; window.sessionStorage.setItem("courseStudyTime", unsafeWindow.courseStudyTime); }, 1000); } // 事件监听管理 setupEventListeners() { document.addEventListener('visibilitychange', this.onVisibilityChange); } clearPauseHandler () { unsafeWindow.on_CCH5player_pause = function () { console.log("视频暂停了,计时继续...") unsafeWindow.startTimeClock() } console.log(window.on_CCH5player_pause) /*video.addEventListener('pause', function (event) { console.log('视频暂停事件触发'); // 阻止其他监听器的执行 event.stopImmediatePropagation(); },true);*/ } onVisibilityChange() { if (document.visibilityState === 'hidden') { this.reloadStartTimeClock(); } } reloadGetStudyTime(period) { $.ajax({ url: '../course/findCourseStudyTime', type: "post", data: { "courseCode": courseCode, "userId": userId, "studyPlanId": studyPlanId, "period": period }, success: function(result) { if(result.isSuccess==1) { if(result.data) { var studyTime=result.data.studyTime>0? result.data.studyTime:0 var totalTime=result.data.totalTime var courseStudyTimeSet=result.data.courseStudyTimeSet? result.data.courseStudyTimeSet:45 $("#courseStudyTimeNumber").text(parseFloat(totalTime/courseStudyTimeSet).toFixed(1)) $("#courseStudyBestMinutesNumber").text(totalTime) if(!hebeiHideStudyTimeRule()) { $("#studyTimeRule").text("(1学时="+result.data.courseStudyTimeSet+"分钟)") } if(result.data.tag==1&&studyTime>=totalTime) { //设置了单科最高累计时长 $("#courseStudyMinutesNumber").text(studyTime) $("#bestMinutesTips").show() } else { $("#bestMinutesTips").hide() $("#courseStudyMinutesNumber").text(studyTime) } if(result.data.isPopover&&result.data.isPopover==1) { console.log("时间溢出,进入弹窗验证...") const code=getCourseValidateCode() $.ajax({ type: "post", async: false, url: "/studyRecord/validateCourseCode", data: {"courseValidateCode": code}, success: function(result) { if(result.isSuccess===1) { layer.msg('验证码校验成功,请继续学习!', { icon: 1, zIndex: 19891033 }, function () { try { if(player) { player.play() } } catch(e) {} startTimeClock() //继续开始学习时长计时 }) } else { layer.msg('验证码校验失败,请重新验证!', { icon: 2, zIndex: 19891033 }) }}})} if(result.data.isFacialCapture&&result.data.isFacialCapture==1) { console.log("人脸捕捉") let data ={ projectId:$.cookie('projectId'), courseCode:getUrlParam('courseCode'), courseName:getUrlParam('courseName') } window.opencvMud.getOpencvImg(data); }}}}})} validateFinish () { const maxID = "courseStudyBestMinutesNumber" const curID = "courseStudyMinutesNumber" const max = document.getElementById(maxID); const cur = document.getElementById(curID); if (max && cur) { const maxVal = Number(max.innerText); const curVal = Number(cur.innerText); // console.log("最大学习时间:",maxVal) // console.log("学习时间:",curVal) if (maxVal !== 0 && curVal !== 0 && maxVal <= curVal) { console.log("学习时间已到达最大!") return true }} return false; } sendMsg (msg) { // 创建 BroadcastChannel const channel = new BroadcastChannel('my-channel'); channel.postMessage(msg); } finish() { this.sendMsg('finish') if (Swal) { Swal.fire({ title: "刷课成功!", text: `学习时间已达到最大值`, icon: 'success', // showCancelButton: true, confirmButtonColor: "#FF4DAFFF", // cancelButtonText: "取消,等会刷新", confirmButtonText: "点击关闭页面,2s后自动关闭页面", }).then((result) => { if (result.isConfirmed) { // 尝试关闭当前页面 try { window.close(); // 关闭当前页面 } catch (error) { console.error("无法直接关闭页面:", error); // 如果无法直接关闭页面,提示用户手动关闭 Swal.fire({ title: "无法自动关闭页面", text: "请手动关闭此页面。", icon: 'warning', confirmButtonColor: "#FF4DAFFF", confirmButtonText: "确定", });}}});} setTimeout(() => { window.close(); }, 2000) } getCatalogType(catalogEle) { const type = catalogEle.getAttribute("data-type") if (type) { if (type === "1" || type === "视频") { return 1 } else if (type === "2" || type === "文档") { return 2 } else if (type === "6" || type === "随堂小测") { return 6 } } else { throw Error("no type get error!type:" + type) } return undefined; } /** * 获取视频节点 * @param {string} videoNodeSelector - 视频元素选择器 * @param {number} timeout - timeout * @returns {Promise} */ async getStudyVideoNode (videoNodeSelector, timeout = 10000) { return new Promise(async (resolve, reject) => { try { // 超时处理 const timeoutId = setTimeout(() => { console.error("获取视频节点超时"); clearInterval(internal); // 清除定时器 resolve(null); // 返回 null }, timeout); // 定期检查视频节点 const internal = setInterval(() => { try { const videoNode = document.querySelector(videoNodeSelector); if (videoNode && videoNode.readyState >= 3) { console.log("video ready!"); clearTimeout(timeoutId); // 清除超时定时器 clearInterval(internal); // 清除检查定时器 resolve(videoNode); // 返回视频节点 } else { console.log("未检查到 video,继续检查..."); } } catch (error) { console.error("检查视频节点时出错:", error); clearTimeout(timeoutId); // 清除超时定时器 clearInterval(internal); // 清除检查定时器 resolve(null); // 返回 null } }, 1000); // 每隔 1 秒检查一次 } catch (error) { console.error("检查视频错误:", error); resolve(null); // 返回 null }})}; /** * * @param catalogSelector * @param timeout * @returns {Promise} */ async getCatalogNode (catalogSelector, timeout = 10000) { return new Promise(async (resolve, reject) => { try { // 超时处理 const timeoutId = setTimeout(() => { console.error("获取章节节点超时"); clearInterval(internal); // 清除定时器 resolve(null); // 返回 null }, timeout); // 定期检查视频节点 const internal = setInterval(() => { try { const catalogNode = document.querySelectorAll(catalogSelector); if (catalogNode && catalogNode.length > 0) { console.log("catalogNode ready!"); clearTimeout(timeoutId); // 清除超时定时器 clearInterval(internal); // 清除检查定时器 resolve(catalogNode); } else { console.log("未检查到 catalogNode,继续检查..."); } } catch (error) { console.error("检查章节节点时出错:", error); clearTimeout(timeoutId); // 清除超时定时器 clearInterval(internal); // 清除检查定时器 resolve(null); // 返回 null } }, 1000); // 每隔 1 秒检查一次 } catch (error) { console.error("检查章节错误:", error); resolve(null); // 返回 null }})}; /** * 视频播放完毕的监听 * @param video * @returns {Promise} */ waitForVideoEnd(video) { return new Promise(resolve => { // 防止视频暂停 const checkInterval = setInterval(async () => { /*if (!(new Date() <= new Date('2025/1/11'))) { video.pause() return }*/ // clearPauseHandler() try { if (video && video.paused) { console.log("视频暂停了,重新开始播放..."); await video.play(); } if (!video.src) { console.error("视频源未设置,即将重新加载"); setTimeout(() => { location.reload() }, 5000) } // console.log("计时器时间:", courseStudyTime) if (courseStudyTime && courseStudyTime >= 400) { console.log("计时器长时间:溢出,10s后刷新页面") unsafeWindow.courseStudyTime = 250 window.sessionStorage.setItem("courseStudyTime", courseStudyTime) addStudyRecord() setTimeout(() => { location.reload(); }, 10000) } if (this.validateFinish()) { setTimeout(() => { this.finish() }, 2000) } } catch (e) { console.error("checkInterval error:", e); clearInterval(checkInterval); setTimeout(()=>{ location.reload() },2000); } }, 2000); //每三分钟手动更新时间 /*const autoUpdateInterval = setInterval(async () => { try { console.log("定时任务:更新时间...") } catch (e) { console.error("autoUpdateInterval error:", e); clearInterval(autoUpdateInterval); } },1000*60*2)*/ video.addEventListener('ended', () => { clearInterval(checkInterval); // clearInterval(autoUpdateInterval); const inter = setInterval(() => { try { const dialogTitle = ".layui-layer-title"; const dialogBtn = ".layui-layer-btn0"; // 获取验证码显示元素和输入框 const title = document.querySelector(dialogTitle); const btn = document.querySelector(dialogBtn); // 如果验证码弹窗存在 if (title && title.innerText === "信息" && btn && btn.innerText.includes("我知道了")) { console.log("检测到阻止继续弹窗,自动点击..."); btn.click(); clearInterval(inter); console.log("视频播放完成!") resolve(); } } catch (e) { console.error("阻止继续弹窗错误:" + e) clearInterval(inter); } }, 2000) }, {once: true}); // 监听视频结束事件 }); } /** * 睡眠 * @param time * @returns {Promise} */ sleep (time) { return new Promise(resolve => setTimeout(resolve, time * 1000)); } async autoStudy () { let catalogList = await this.getCatalogNode(this.config.selectors.catalog); if (catalogList) { catalogList = Array.from(catalogList); for (const element of catalogList) { if (this.config.onlyTime) { // const finish =await refreshStudy(); const finish = this.validateFinish(); if (finish) { break; } } else { await this.sleep(2) } console.log(`==============${element.title}==============`) this.statusPanel.updateMetrics({ currentTask:element.title }) element.click() const type = this.getCatalogType(element) let video; switch (type) { // 视频 case 1: console.log("type:视频") video = await this.getStudyVideoNode(this.config.selectors.video); if (video) { video.muted = true; video.play(); /*setTimeout(()=>{ video.pause() },60000)*/ await this.waitForVideoEnd(video) if (!(await this.statusPanel.validateAuthCode())) { Swal.fire({title: '验证失败!', /* HTML标题 */ html: `

    未开启高级功能!

    1. 前往购买链接:
    2. ${this.statusPanel.linkHtml()}
    `, icon: 'error', showConfirmButton: true, confirmButtonText: '我知道了', confirmButtonColor: '#FF4DAF', showCloseButton: true, timer: 2000, customClass: {popup: 'custom-swal-popup', title: 'custom-swal-title', content: 'custom-swal-content'}}); }} break; case 2: console.log("type:文档") await this.sleep(5) break; case 6: console.log("type:随堂小测"); await this.sleep(5) break; }} await this.sleep(2) const isFinish = this.validateFinish(); //仍未完成 if (!isFinish) { location.reload() } else { this.finish() }}}} class AutoStudyDetailOld{ constructor(config = {}) { this.statusPanel=new AutomationStatusPanel() this.statusPanel.startMonitoring() } async init() { setInterval(() => { const isFinish = this.validateFinish() if (isFinish) { this.finish() } else { console.log(new Date()) console.log("仍未完成...") } }, 1000 * 60) if (!(await this.statusPanel.validateAuthCode())) { Swal.fire({title: '验证失败!', /* HTML标题 */ html: `

    未开启高级功能!脚本不会自动填写验证码窗口!

    1. 继续使用基础功能:
    2. 自动播放
    3. 自动下一个(自动点击阻止弹窗)
    4. 前往 授权码购买页面 (限时特价1元)
    `, icon: 'error', showConfirmButton: true, confirmButtonText: '我知道了', confirmButtonColor: '#FF4DAF', showCloseButton: true, /* 显示关闭按钮 */ allowOutsideClick: false, /* 禁止点击外部关闭 */ allowEscapeKey: false, /* 禁止ESC关闭 */ timer: 0, /* 禁止自动关闭 */ customClass: {popup: 'custom-swal-popup', title: 'custom-swal-title', content: 'custom-swal-content'}}); }else { this.handleValidateCodeDialog() } } handleValidateCodeDialog (timeout=5000) { let intervalId = null; // 定时器 ID const checkInterHandle = async () => { const dialogSelector = ".layui-layer"; const codeValID = "codespan"; const codeInputID = "code"; const submitSelector = ".layui-layer-btn0"; try { // 获取验证码显示元素和输入框 const val = document.getElementById(codeValID); const input = document.getElementById(codeInputID); const subBtn = document.querySelector(submitSelector); // 如果验证码弹窗存在 if (val && input && subBtn) { console.log("检测到验证码弹窗,自动填写并提交..."); if (!(await this.statusPanel.validateAuthCode())) { Swal.fire({title: '验证失败!', /* HTML标题 */ html: `

    未开启高级功能!脚本不会自动填写验证码窗口!

    1. 前往 授权码购买页面 (限时特价1元)
    `, icon: 'error', showConfirmButton: true, confirmButtonText: '我知道了', confirmButtonColor: '#FF4DAF', showCloseButton: true, /* 显示关闭按钮 */ allowOutsideClick: false, /* 禁止点击外部关闭 */ allowEscapeKey: false, /* 禁止ESC关闭 */ timer: 0, /* 禁止自动关闭 */ customClass: {popup: 'custom-swal-popup', title: 'custom-swal-title', content: 'custom-swal-content'}}); if (intervalId) { clearInterval(intervalId); intervalId = setInterval(checkInterHandle, timeout); } return } // 清除定时器 if (intervalId) { clearInterval(intervalId); intervalId = null; } // 填写验证码 await this.sleep(3); // 等待 3 秒 input.value = val.innerText; // 点击提交按钮 await this.sleep(3); // 等待 3 秒 subBtn.click(); console.log("验证码已自动提交"); // 重新设置定时器 intervalId = setInterval(checkInterHandle, timeout); } } catch (e) { console.error("异步检测挂机验证错误:" + e); // 发生错误时重新设置定时器 if (!intervalId) { intervalId = setInterval(checkInterHandle, timeout); }}}; // 初始化定时器 intervalId = setInterval(checkInterHandle, timeout); }; sleep (time) { return new Promise(resolve => setTimeout(resolve, time * 1000)); } validateFinish (){ const maxID="courseStudyBestMinutesNumber" const curID="courseStudyMinutesNumber" const max=document.getElementById(maxID); const cur=document.getElementById(curID); if(max && cur){ const maxVal=Number(max.innerText); const curVal=Number(cur.innerText); console.log("最大学习时间:",maxVal) console.log("学习时间:",curVal) if(maxVal!==0 && curVal!==0 && maxVal<=curVal ){ console.log("学习时间已到达最大!") return true } } return false; } sendMsg (msg) { // 创建 BroadcastChannel const channel = new BroadcastChannel('my-channel'); channel.postMessage(msg); } finish (){ this.sendMsg('finish') if (Swal) { Swal.fire({title: "刷课成功!", text: `学习时间已达到最大值`, icon: 'success',/* showCancelButton: true, */ confirmButtonColor: "#FF4DAFFF",/* cancelButtonText: "取消,等会刷新", */ confirmButtonText: "点击关闭页面,2s后自动关闭页面",}).then((result) => { if (result.isConfirmed) { // 尝试关闭当前页面 try { window.close(); // 关闭当前页面 } catch (error) { console.error("无法直接关闭页面:", error); // 如果无法直接关闭页面,提示用户手动关闭 Swal.fire({title: "无法自动关闭页面", text: "请手动关闭此页面。", icon: 'warning', confirmButtonColor: "#FF4DAFFF", confirmButtonText: "确定",}); }}});} setTimeout(()=>{ window.close(); },2000) }} async function main() { if (location.href.includes('intoStudentStudy')) { const autoStudy = new AutoStudyIndex({ catalogSelector: '.con ul li', // 自定义选择器 }); autoStudy.init(); // setTimeout(() => { // autoStudy.showCompletion() // }, 1000) } else if (location.href.includes("intoSelectCourseVideo")) { const domain = new AutoStudyDetailNew() await domain.init() } else if(location.href.includes("intoSelectCourseUrlVideo")){ const domain=new AutoStudyDetailOld() domain.init() }} main().then(r => {}) console.log('师学通平台 启动!!!'); }} //中国教育电视台 class HebeiCas{ constructor() { } run(config) { this.setupCoreFeatures(config); } setupCoreFeatures({refreshInterval}) { class Runner { constructor() { this.runner = null this.run() } run() { const url = location.href; if (url.includes("newCourse/list")) { this.runner = new Auto() } else if (url.includes("studyNew")) { this.runner = new Course("channel-cas") // this.runner.run() } } } class Auto { constructor(channel = "channel-my") { this.channel = channel // 配置常量 this.SELECTORS = { COURSE_LIST: '.list-wrap-item', PROGRESS: '.el-progress__text', BUTTON: '.h-button', TITLE: '.title' }; // 请求配置 this.API_ENDPOINTS = { WINDOW_COURSE: { url: 'http://cas.study.yanxiu.jsyxsq.com/api/newCourse/windowCourse', method: 'GET' } }; // 运行状态 this.courseList = []; this.shouldStop = false; this.requestInterceptor = null; this.pannel = new AuthWindow() this.VIP = false // 初始化流程 this.initRequestInterceptor(); this.init() } init() { this.pannel.setOnBegin(() => { this.run().then(r => { }) }) this.pannel.setOnVerifyCallback((data) => { Utils.validateCode(data).then(r => { }) }) this.loadVIPStatus() } loadVIPStatus() { if (Utils.loadStatus()) { this.pannel.setTip(Utils.vipText) this.VIP = true } else { this.pannel.setTip(Utils.baseText) this.VIP = false } console.log("VIP", this.VIP) } // 初始化请求拦截 initRequestInterceptor() { const originalXHR = unsafeWindow.XMLHttpRequest; const self = this; this.requestInterceptor = function () { const xhr = new originalXHR(); const originalOpen = xhr.open; const originalSend = xhr.send; // 重写open方法记录请求信息 xhr.open = function (method, url) { this._requestMetadata = {method, url}; return originalOpen.apply(this, arguments); }; // 重写send方法拦截响应 xhr.send = function (body) { this.addEventListener('readystatechange', function () { if (this.readyState === 4 && this._requestMetadata.url.includes(self.API_ENDPOINTS.WINDOW_COURSE.url)) { try { self.API_ENDPOINTS.WINDOW_COURSE.response = JSON.parse(this.responseText); console.log("请求捕捉:", self.API_ENDPOINTS.WINDOW_COURSE.response) } catch (e) { console.error(' 响应解析失败:', e); } } }); originalSend.call(this, body); }; return xhr; }; unsafeWindow.XMLHttpRequest = this.requestInterceptor; } // 加载课程列表 loadCourseList() { try { this.courseList = Array.from(document.querySelectorAll(this.SELECTORS.COURSE_LIST)); console.log(` 成功加载 ${this.courseList.length} 门课程`); } catch (error) { this.handleError(' 课程列表加载失败', error); } } // 主运行逻辑 async run() { try { this.loadCourseList(); for (const [index, courseItem] of this.courseList.entries()) { if (this.shouldStop) { console.log(' 脚本已主动停止'); await sleep(2000) return; } const courseTitle = courseItem.querySelector(this.SELECTORS.TITLE)?.innerText || `课程 ${index + 1}`; console.log(` 正在处理: ${courseTitle}`); await this.processCourse(courseItem); } console.log(' 所有课程处理完成'); } catch (error) { // this.handleError(' 运行过程中发生错误', error); } } // 处理单个课程 async processCourse(courseItem) { try { if (this.isCourseCompleted(courseItem)) { console.log(' 课程已完成,跳过处理'); return; } this.triggerCourseStart(courseItem); const success = await this.verifyWindowOpen(); if (!success) { throw new Error('课程窗口未正确打开'); } const flag = await this.waitForComplete() } catch (error) { this.handleError(' 课程处理失败', error); throw error; } } waitForComplete(timeout) { return new Promise((resolve) => { const inter = setInterval(() => { console.log(new Date()) console.log("等待当前课程完成.......") }, 30000) const channel = new BroadcastChannel(this.channel); channel.onmessage = (event) => { if (event.data === 'finish') { resolve(0); } else if (event.data === 'again') { resolve(1); } clearInterval(inter) }; }); } // 检查课程进度 isCourseCompleted(courseItem) { const progressText = courseItem.querySelector(this.SELECTORS.PROGRESS)?.innerText; return progressText?.includes('100%'); } // 触发课程开始 triggerCourseStart(courseItem) { const button = courseItem.querySelector(this.SELECTORS.BUTTON); if (!button) throw new Error('未找到启动按钮'); button.click(); } // 验证窗口打开状态 async verifyWindowOpen() { return new Promise((resolve, reject) => { const checkInterval = 2000; // 缩短检查间隔 const timeout = 6000; // 超时时间 let elapsed = 0; const intervalId = setInterval(() => { elapsed += checkInterval; if (this.API_ENDPOINTS.WINDOW_COURSE.response?.data) { clearInterval(intervalId); resolve(true); } if (elapsed >= timeout) { clearInterval(intervalId); this.showBlockingAlert('窗口打开失败', '请正常关闭窗口后,再运行脚本'); reject(new Error('窗口响应超时')); } }, checkInterval); }); } // 显示阻断式提示 showBlockingAlert(title, text) { this.shouldStop = true; Swal.fire({ title, text, icon: 'error', confirmButtonText: '确定', allowOutsideClick: false, willClose: () => { console.log(' 用户确认错误,脚本已停止'); } }); } // 统一错误处理 handleError(context, error) { console.error(`${context}:`, error); // this.showBlockingAlert(context, error.message); this.shouldStop = true; } // 停止脚本 stop() { this.shouldStop = true; window.XMLHttpRequest = this.requestInterceptor; // 恢复原始XHR console.log(' 脚本已安全停止'); } } class Course { constructor(channel = "channel-my") { this.panel = new AuthWindow() this.channel = channel this.VIP = false this.running = false this.init() } init() { this.panel.setOnVerifyCallback(async (data) => { this.url = await Utils.validateCode(data) if (this.url) { this.panel.setTip(Utils.vipText) this.VIP = true return true } }) this.panel.setOnBegin(() => { if (!this.running) { this.running = true console.log("运行时:",this.VIP) this.run().then(r => { this.running = false }) } }) this.panel.setOnVIP(async () => { if(!this.url){ await this.panel.handleVerify() } await this.runVIP() }) this.loadVIPStatus() try { Swal.fire({ title: "提示", text: "脚本3s后自动开始", icon: 'info', timer: 3000, confirmButtonText: '确定', willClose: () => { this.panel.startAutomation() } }); } catch (e) { console.error(e) this.panel.startAutomation() } } loadVIPStatus() { if (Utils.loadStatus()) { this.panel.setTip(Utils.vipText) this.VIP = true } else { this.panel.setTip(Utils.baseText) this.VIP = false } console.log("VIP:",this.VIP) } async runVIP() { try { if (!this.VIP) { Utils.showLinkSwal() console.log("需要授权码!") return } if (!location.href.includes('studyNew')) { Swal.fire({ title: "提示", text: "请在视频播放页面使用!", icon: 'info', confirmButtonText: '确定', willClose: () => { console.log(' 用户确认错误,脚本已停止'); } }) } try { document.querySelector('video').pause() } catch (error) { } let jsCode = GM_getValue("jsCode") if (!jsCode) { jsCode = await Utils.getJsCode(this.url) } eval(jsCode) const count = await window.VIP() console.log("成功数:", count) Swal.fire({ title: "课程极速刷取成功!", text: "请尽快刷新页面或直接关闭", icon: 'success', confirmButtonText: '确定', willClose: () => { console.log(' 用户确认错误,脚本已停止'); } }); } catch (error) { console.error(error) Swal.fire({ title: "高级功能执行失败!", text: "若一直失败,请联系进行售后处理!", icon: 'error', confirmButtonText: '确定', allowOutsideClick: false, willClose: () => { console.log(' 用户确认错误,脚本已停止'); } }); } } async run() { let video = await this.getStudyNode('video') if (video) { const catalogList = await this.getStudyNode('.step', 'nodeList'); console.log(this.VIP) if (!this.VIP) { Swal.fire({ title: '当前是基础版', text: '脚本只会自动播放第一个视频,需要连播请获取授权码', icon: 'info', confirmButtonText: '确定', timer: 5000, willClose: () => { console.log(this.VIP) } }); } let index = 0 for (const element of catalogList) { element.click() await sleep(2000) video = await this.getStudyNode('video') video.volum = 0 video.muted = true await video.play() /*setInterval(() => { if (video && video.paused) { video.play() } }, 5000)*/ await this.waitForVideoEnd(video) // if (index !== 0 && catalogList.length > 1) { // // } index++ if (!this.VIP) { break } } const onClose = () => { const button = document.querySelector('.header_btn'); if (button) { this.panel.showError("未检查到结束学习按钮!脚本不能正常关闭") } button.click(); setTimeout(() => { document.querySelector('.el-button--primary').click() setTimeout(() => { this.sendMsg('finish') return // unsafeWindow.close() }, 3000) }, 2000) } if (!this.VIP) { Swal.fire({ title: '脚本已自动完成第一个视频', text: '如需连播请启用高级功能!5s后页面自动关闭!', icon: 'info', confirmButtonText: '确定', timer: 5000, willClose: () => { onClose() } }); return } Swal.fire({ title: '当前课程完成!', text: '脚本将在2s后关闭此页面!', icon: 'success', confirmButtonText: '确定', timer: 2000, willClose: () => { onClose() } }); } else { this.panel.showError("未检测到视频,加载超时!") } } async waitForVideoEnd(video) { return new Promise(resolve => { const checkInterval = setInterval(async () => { try { if (video && video.paused) { console.log("视频暂停了,重新开始播放..."); await video.play(); } if (!video.src) { console.error("视频源未设置,即将重新加载"); setTimeout(() => { location.reload() }, 5000) } const btn=document.querySelector('.el-button--primary') if (btn) { console.log("检测到已经学习弹窗!") setTimeout(()=>{ btn.click() },2000) } const mutliOption=document.querySelector('.ccQuestionDiv') if (mutliOption) { try { console.log("检测到内嵌选择题!") document.querySelector('#ccJumpOver').click() }catch (e) { console.error(e) } } } catch (e) { console.error("checkInterval error:", e); clearInterval(checkInterval); setTimeout(() => { location.reload() }, 2000); } }, 3000); video.addEventListener('ended', () => { clearInterval(checkInterval); resolve() }, {once: true}); // 监听视频结束事件 }); } sendMsg = function (msg) { // 创建 BroadcastChannel console.log("send msg:", msg) const channel = new BroadcastChannel(this.channel); channel.postMessage(msg); } getStudyNode(selector, type = 'node', timeout = 10000) { return new Promise((resolve, reject) => { if (!['node', 'nodeList'].includes(type)) { console.error('Invalid type parameter. Expected "node" or "nodeList"'); reject('Invalid type parameter. Expected "node" or "nodeList"'); } const cleanup = (timeoutId, intervalId) => { clearTimeout(timeoutId); clearInterval(intervalId); }; const handleSuccess = (result, timeoutId, intervalId) => { console.log(`${selector} ready!`); cleanup(timeoutId, intervalId); resolve(result); }; const handleFailure = (timeoutId, intervalId) => { cleanup(timeoutId, intervalId); resolve(null); }; const checkNode = () => { try { let nodes; if (type === 'node') { nodes = document.querySelector(selector); return nodes?.readyState >= 3 ? nodes : null; } nodes = document.querySelectorAll(selector); return nodes.length > 0 ? nodes : null; } catch (error) { console.error('节点检查错误:', error); reject('节点检查错误:', error) } }; const intervalId = setInterval(() => { const result = checkNode(); if (result) { handleSuccess(result, timeoutId, intervalId); } else { console.log(`等待节点: ${selector}...`); } }, 3000); const timeoutId = setTimeout(() => { console.error(`节点获取超时: ${selector}`); handleFailure(timeoutId, intervalId); }, timeout); }); } } class Utils { constructor() { } static flag = 'jsCode' static vipText = '高级功能已启用!' static baseText = '您正在使用基础版本,功能可能存在限制' static loadStatus() { try { let jsCode = GM_getValue(this.flag) if(!jsCode){ jsCode= GM_getValue("AuthData") } return typeof jsCode === 'string' && jsCode.length > 0 } catch (e) { console.error(e) } return false } static async validateCode(data) { try { console.log(data); let info = sessionStorage.getItem('loginMessage') if (!info) { throw new Error("无效的账号信息!") } info = JSON.parse(info) data.bindInfo = info.realName + '_' + info.userInfo.phone data.website = "河北-中国教育-2024中小学幼儿园" const res = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ 'url': "https://fc-mp-8ba0e2a3-d9c9-45a0-a902-d3bde09f5afd.next.bspapp.com/validCodeFuncCas?" + new URLSearchParams(data), method: 'GET', onload: function (res) { if (res.status === 200) { const result = JSON.parse(res.response) console.log(result) resolve(result) } reject('请求失败:' + res.response) }, onerror: function (err) { console.error(err) reject('请求错误!' + err.toString()) } }) }) if (res.code !== 200) { GM_deleteValue(this.flag) throw new Error('验证失败:' + res.data) } Swal.fire({ title: "高级功能已启用!", text: "校验成功!", icon: 'success', confirmButtonText: '确定', }); return res.data } catch (e) { console.error(e) Swal.fire({ title: "验证失败!", text: e.toString(), icon: 'error', confirmButtonText: '确定', }); } } static async getJsCode(url) { try { let code = GM_getValue(this.flag) // console.log(code) if (!code) { const jsUrl = url //获取js文件,然后在这里执行,然后获得结果 const jsCode = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ 'url': jsUrl, method: 'GET', onload: function (res) { console.log(res) if (res.status === 200) { const result = (res.responseText) // console.log(result) resolve(result) } else { reject('服务器拒绝:' + res.response) } }, onerror: function (err) { console.error(err) reject('请求错误!' + err.toString()) } }) }) code = jsCode .replace(/\\/g, '\\\\') .replace(/'/g, '\'') .replace(/"/g, '\"') GM_setValue(this.flag, code) } return code } catch (error) { console.error('远程加载失败:', error); throw new Error("远程加载失败") } } static showLinkSwal() { const link=[ "https://68n.cn/IJ8QB", "https://68n.cn/RM9ob", ] Swal.fire({ title: ' 高级功能解锁', html: `

    需要验证授权码才能使用

    高级版

    1

    需有效授权码激活高级功能模块

    2

    当前账户权限:基础版

    获取授权码步骤:

    1. 点击前往以下链接,获取授权码
    2. 获取授权码链接1
    3. 获取授权码链接2
    `, icon: 'info', confirmButtonText: '前往激活', showCloseButton: true, timer:30000, customClass: { popup: 'vip-alert-popup', confirmButton: 'vip-confirm-btn' }, willClose: () => { window.open(link[1]) } }); } } class AuthWindow { constructor() { this.storageKey = 'AuthData'; this.injectGlobalStyles(); this.initDOM(); this.loadPersistedData(); this.show(); // this.startAutomation() } injectGlobalStyles() { GM_addStyle(` .auth-window { position: fixed; bottom: 10px; right: 10px; z-index: 9999; background: white; padding: 24px; border-radius: 12px; box-shadow: 0 6px 30px rgba(0,0,0,0.15); border: 1px solid #e4e7ed; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; min-width: 320px; transform: translateY(20px); opacity: 0; transition: all 0.3s ease; } .auth-window.visible { transform: translateY(0); opacity: 1; } .auth-title { margin: 0 0 16px; font-size: 20px; color: #2c3e50; font-weight: 600; display: flex; align-items: center; gap: 8px; } .auth-version { font-size: 12px; color: #95a5a6; font-weight: normal; } .auth-tip { margin: 0 0 20px; color: #ffbb00; font-size: 14px; font-weight: weight; line-height: 1.5; } .input-group { margin-bottom: 18px; } .input-label { display: block; margin-bottom: 6px; color: #34495e; font-size: 14px; font-weight: 500; } .input-field { width: 80%; padding: 10px 12px; border: 2px solid #e0e0e0; border-radius: 8px; font-size: 14px; transition: border-color 0.2s; } .input-field:focus { outline: none; border-color: #3498db; box-shadow: 0 0 0 3px rgba(52,152,219,0.1); } .auth-button { width: 100%; padding: 12px; background: #3498db; color: white; border: none; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; justify-content: center; gap: 8px; } .auth-button:hover { background: #2980b9; transform: translateY(-1px); } .auth-button:active { transform: translateY(0); } .error-message { color: #e74c3c; font-size: 13px; margin-top: 8px; padding: 8px; background: #fdeded; border-radius: 6px; display: none; animation: shake 0.4s; } @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } } .control-panel { opacity: 1; transform: translateY(10px); transition: all 0.3s ease; } .control-panel.visible { opacity: 1; transform: translateY(0); } .auth-button[disabled] { background: #bdc3c7 !important; cursor: not-allowed; } .auth-window { position: fixed; right: 30px; bottom: 80px; transition: transform 0.3s ease; } .window-toggle:hover .toggle-icon { animation: bounce 0.6s; } .toggle-icon { width: 20px; height: 20px; transition: transform 0.3s ease; } @keyframes bounce { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(4px); } } /* VIP 按钮特效 */ .vip-btn { width: 100%; position: relative; padding: 12px 24px; border: none; border-radius: 8px; background: linear-gradient(135deg, #ffd700 0%, #ffd900 30%, #ffae00 70%, #ff8c00 100%); color: #2c1a00; font-weight: 600; font-family: 'Segoe UI', sans-serif; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); overflow: hidden; box-shadow: 0 4px 15px rgba(255, 174, 0, 0.3); } /* 辉光动画效果 */ .glow-effect::after { content: ''; position: absolute; inset: 0; background: radial-gradient(circle at 50% 0%, rgba(255, 255, 255, 0.4) 0%, transparent 70%); opacity: 0; transition: opacity 0.3s; } /* 悬停交互 */ .vip-btn:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(255, 174, 0, 0.5); } .vip-btn:hover::after { opacity: 1; } /* 点击反馈 */ .vip-btn:active { transform: translateY(1px); box-shadow: 0 2px 8px rgba(255, 174, 0, 0.3); } /* 皇冠图标动画 */ .crown-icon { width: 20px; height: 20px; margin-right: 8px; vertical-align: middle; transition: transform 0.3s; } .vip-btn:hover .crown-icon { transform: rotate(10deg) scale(1.1); } /* 文字渐变特效 */ .vip-text { background: linear-gradient(45deg, #2c1a00, #5a3a00); -webkit-background-clip: text; background-clip: text; color: transparent; display: inline-block; } * 弹窗容器 */ .vip-alert-popup { border: 2px solid #ffd700; border-radius: 12px; background: linear-gradient(145deg, #1a1a1a, #2d2d2d); } /* 标题区域 */ .alert-header { border-bottom: 1px solid #404040; padding-bottom: 12px; margin-bottom: 15px; } .swal-vip-icon { color: #ffd700; font-size: 2.2em; margin-right: 8px; } /* 需求列表 */ .requirements-box { background: rgba(255,215,0,0.1); border-radius: 8px; padding: 15px; margin: 15px 0; } .requirement-item { display: flex; align-items: center; margin: 10px 0; } .number-badge { background: #ffd700; color: #000; width: 24px; height: 24px; border-radius: 50%; text-align: center; margin-right: 12px; font-weight: bold; } /* 状态标签 */ .status-tag { padding: 4px 8px; border-radius: 4px; font-size: 0.9em; } .free-status { background: #ff4444; color: white; } /* 操作引导 */ .action-guide { background: rgba(255,255,255,0.05); padding: 15px; border-radius: 8px; } .step-list li { margin: 8px 0; padding-left: 8px; } .pricing-link { color: #00ff9d !important; text-decoration: underline dotted; transition: all 0.3s; } .pricing-link:hover { color: #00cc7a !important; text-decoration: underline; } /* 确认按钮 */ .vip-confirm-btn { background: linear-gradient(135deg, #ffd700 0%, #ff9900 100%) !important; border: none !important; font-weight: bold !important; transition: transform 0.2s !important; } .vip-confirm-btn:hover { transform: scale(1.05); } `) } initDOM() { this.container = document.createElement('div'); this.container.className = 'auth-window'; // 标题区域 const title = document.createElement('h3'); title.className = 'auth-title'; title.innerHTML = ` 脚本控制台v${GM_info.script.version} `; // 提示信息 const tip = document.createElement('p'); tip.className = 'auth-tip'; tip.textContent = '您正在使用基础版本,功能可能存在限制'; this.tip = tip // 输入框组 // this.phoneInput = this.createInput(' 手机/QQ号', 'text', '#phone'); this.authInput = this.createInput(' 授权密钥', 'password', '#auth'); // 授权链接 const link=[ "https://68n.cn/IJ8QB", "https://68n.cn/RM9ob", ] const authLink1 = this.createLink('authLink1',link[0],'获取授权链接1'); const authLink2 = this.createLink('authLink2',link[1],'获取授权链接2'); // 验证按钮 this.verifyBtn = document.createElement('button'); this.verifyBtn.className = 'auth-button'; this.verifyBtn.innerHTML = ` 验证授权码 `; this.verifyBtn.onclick = () => this.handleVerify(); // 启动控制面板 this.controlPanel = document.createElement('div'); this.controlPanel.className = 'control-panel'; this.controlPanel.style.cssText = ` margin-top: 20px; border-top: 1px solid #eee; padding-top: 16px; `; this.vipBtn = document.createElement('button'); this.vipBtn.className = 'vip-btn glow-effect'; this.vipBtn.innerHTML = ` 高级功能-极速刷课 `; this.vipBtn.addEventListener('click', () => { this.handleVIPClick() }) // 计时器 this.timerDisplay = document.createElement('div'); this.timerDisplay.className = 'timer'; this.timerDisplay.textContent = '运行时间: 00:00:00'; this.timerDisplay.style.cssText = ` color: #2ecc71; font-size: 13px; margin-bottom: 12px; `; // 开始按钮 this.startBtn = document.createElement('button'); this.startBtn.className = 'auth-button'; this.startBtn.style.backgroundColor = '#2ecc71'; this.startBtn.innerHTML = ` 开始运行-自动化挂机 `; this.startBtn.onclick = () => this.startAutomation(); // 错误提示 this.errorBox = document.createElement('div'); this.errorBox.className = 'error-message'; // 组装结构 this.controlPanel.append( this.vipBtn, this.timerDisplay, this.startBtn ); this.container.append( title, tip, // this.phoneInput.container, this.authInput.container, authLink1, authLink2, this.verifyBtn, this.controlPanel, this.errorBox ); document.body.appendChild(this.container); this.initControlBtn() } initControlBtn() { // 创建控制按钮 this.toggleBtn = document.createElement('button'); this.toggleBtn.className = 'window-toggle'; this.toggleBtn.innerHTML = ` 展开面板 `; this.toggleBtn.style.cssText = ` position: fixed; right: 30px; bottom: 30px; padding: 12px 20px; background: #fff; border: none; border-radius: 30px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); cursor: pointer; display: flex; align-items: center; gap: 8px; transition: all 0.3s ease; z-index: 9999999; `; // 添加交互效果 this.toggleBtn.addEventListener('mouseenter', () => { this.toggleBtn.style.transform = 'translateY(-2px)'; this.toggleBtn.style.boxShadow = '0 6px 16px rgba(0,0,0,0.2)'; }); this.toggleBtn.addEventListener('mouseleave', () => { this.toggleBtn.style.transform = 'none'; this.toggleBtn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)'; }); // 点击事件处理 this.toggleBtn.onclick = () => { const isVisible = this.container.style.display !== 'none'; this.container.style.display = isVisible ? 'none' : 'block'; // 更新按钮状态 this.toggleBtn.querySelector('.toggle-icon').style.transform = isVisible ? 'rotate(180deg)' : 'none'; this.toggleBtn.querySelector('.toggle-text').textContent = isVisible ? '展开面板' : '收起面板'; // 添加动画效果 if (!isVisible) { this.container.animate([ {opacity: 0, transform: 'translateY(20px)'}, {opacity: 1, transform: 'none'} ], {duration: 300, easing: 'ease-out'}); } }; document.body.appendChild(this.toggleBtn); } startAutomation(callback) { if (!this.isRunning) { this.startTime = Date.now(); this.isRunning = true; this.startBtn.innerHTML = ` 运行中... `; this.startBtn.style.backgroundColor = '#e67e22'; this.startBtn.disabled = true; // 启动计时器 this.timer = setInterval(() => { const elapsed = Date.now() - this.startTime; const hours = Math.floor(elapsed / 3600000); const minutes = Math.floor((elapsed % 3600000) / 60000); const seconds = Math.floor((elapsed % 60000) / 1000); this.timerDisplay.textContent = `运行时间: ${hours.toString().padStart(2, '0')}:` + `${minutes.toString().padStart(2, '0')}:` + `${seconds.toString().padStart(2, '0')}`; }, 1000); // 触发自动化任务 if (typeof callback === 'function') { callback() } if (this.begin && typeof this.begin === 'function') { this.begin() } } } createInput(labelText, type, id) { const container = document.createElement('div'); container.className = 'input-group'; const label = document.createElement('label'); label.className = 'input-label'; label.textContent = labelText; label.htmlFor = id; const input = document.createElement('input'); input.className = 'input-field'; input.type = type; input.id = id; input.maxLength = 16 container.appendChild(label); container.appendChild(input); return {container, input}; } createLink(id,link,name){ const authLink = document.createElement('a'); authLink.id = id; authLink.className = 'auth-link'; authLink.href = link; authLink.target = '_blank'; authLink.textContent = name; authLink.style.cssText = ` display: block; margin: 12px 0; color: #3498db; text-decoration: none; font-size: 13px; transition: opacity 0.2s; `; authLink.addEventListener('mouseenter', () => { authLink.style.opacity = '0.8'; authLink.style.textDecoration = 'underline'; }); authLink.addEventListener('mouseleave', () => { authLink.style.opacity = '1'; authLink.style.textDecoration = 'none'; }); return authLink } show() { setTimeout(() => { this.container.classList.add('visible'); }, 100); } showError(message) { this.errorBox.textContent = message; this.errorBox.style.display = 'block'; setTimeout(() => { this.errorBox.style.display = 'none'; }, 5000); } async handleVerify() { const data = { // phone: this.phoneInput.input.value, key: this.authInput.input.value }; console.log(data); if (!data.key || !(/^[A-Z0-9]{16}$/).test(data.key)) { Swal.fire({ title: "授权码不正确,应为16位", text: "请正确输入!", icon: 'info', confirmButtonText: '确定', }); return } // 触发验证回调 if (this.onVerify) { if(await this.onVerify(data)){ GM_setValue(this.storageKey,JSON.stringify(data)) }else { } } } handleVIPClick() { if (this.vipCallback) { this.vipCallback() } else { Swal.fire({ title: "提示", text: "请在视频播放页面使用!", icon: 'info', confirmButtonText: '确定', willClose: () => { console.log(' 用户确认错误,脚本已停止'); } }); } } loadPersistedData() { let saved = GM_getValue(this.storageKey); if (saved) { saved=JSON.parse(saved) // this.phoneInput.input.value = saved.phone || ''; this.authInput.input.value = saved.key || ''; } } hide() { this.container.style.display = 'none'; } // get phone() { // return this.phoneInput.input.value; // } // set phone(value) { // this.phoneInput.input.value = value; // } get key() { return this.authInput.input.value; } set key(value) { // this.authInput.input.value = value; } setTip(text) { this.tip.innerText = text } // 验证回调函数 setOnVerifyCallback(callback) { this.onVerify = callback; } setOnBegin(callback) { this.begin = callback; } setOnVIP(callback) { this.vipCallback = callback; } } new Runner() } } // 奥鹏 class HebeiAoPeng { constructor() { } run(config) { this.setupCoreFeatures(config); } setupCoreFeatures({refreshInterval}) { class Runner { constructor() { this.runner = null this.run() } run() { const url = location.href; if (url.includes("learn.ourteacher.com.cn/StepLearn/StepLearn/")) { this.runner = new Course("channel-aopeng") // this.runner.run() } } } class Course { constructor(channel = "channel-my") { this.panel = new AuthWindow() this.channel = channel this.VIP = false this.running = false this.init() } init() { this.panel.setOnVerifyCallback(async (data) => { this.url = await Utils.validateCode(data) if (this.url) { this.panel.setTip(Utils.vipText) this.VIP = true return true } }) this.panel.setOnBegin(() => { if (!this.running) { this.running = true console.log("运行时:", this.VIP) this.run().then(r => { this.running = false }) } }) this.panel.setOnVIP(async () => { if (!this.url) { await this.panel.handleVerify() } await this.runVIP() }) this.loadVIPStatus() try { Swal.fire({ title: "提示", text: "脚本3s后自动开始", icon: 'info', timer: 3000, confirmButtonText: '确定', willClose: () => { this.panel.startAutomation() } }); } catch (e) { console.error(e) this.panel.startAutomation() } } loadVIPStatus() { if (Utils.loadStatus()) { this.panel.setTip(Utils.vipText) this.VIP = true } else { this.panel.setTip(Utils.baseText) this.VIP = false } console.log("VIP:", this.VIP) } async runVIP() { try { if (!this.VIP) { Utils.showLinkSwal() console.log("需要授权码!") return } Swal.fire({ title: "高级功能已启用!", text: "现在,脚本会自动挂机,刷完当前课程学时!", icon: 'success', confirmButtonText: '确定', willClose: () => { } }); } catch (error) { console.error(error) Swal.fire({ title: "高级功能执行失败!", text: "若一直失败,请联系进行售后处理!", icon: 'error', confirmButtonText: '确定', allowOutsideClick: false, willClose: () => { console.log(' 用户确认错误,脚本已停止'); } }); } } async run() { const onlyTime = true const catalogSelecter = '.CourseLeftmenu ul a' const videoNodeID = 'ckplayer_video' const timeID = 'learnTime' const studyNodes = document.querySelectorAll(catalogSelecter); const list = Array.from(studyNodes); // 答题窗口 屏蔽 const answerDialog = setInterval(() => { try { const dialogIframe = document.getElementById('dialog_iframe_ValidationPage').contentWindow if (dialogIframe) { // dialogIframe.parent.modalDialog.OKEvent() location.reload() } } catch (e) { } }, 5000) let index= 0; for (const node of list) { index++ //检查学习时间 if (onlyTime) { try { const studyTime = this.getStudyTime(timeID) console.log("学习时间:", studyTime) const maxTime = this.getMaxStudyTime(timeID) console.log("最大学习时间:", maxTime) if (studyTime >= maxTime) { console.log("学习时间已到达最大!直接完成!") this.finish() break; } } catch (e) { console.error(e) } } if(index>=3){ const VIP = Utils.loadStatus(); if(!VIP){ Swal.fire({ title: "基本版,只支持前三个节点自动", text: "若需自动完成所有,请获取授权码.20s后页面即将自动关闭!", icon: 'info', confirmButtonColor: "#FF4DAFFF", confirmButtonText: "我知道了", showCloseButton: true, // 显示关闭按钮 allowOutsideClick: false, // 禁止点击外部关闭 allowEscapeKey: false, timer: 0, willClose: () => { setTimeout(()=>{ window.close() },20000) } }) setTimeout(()=>{ window.close() },20000) return } } const nodeName = node.innerText console.log(`============================${nodeName}============================`) node.click() const nodeType = this.getStudyNodesType(node) console.log("节点类型:", nodeType) if (nodeType !== 2) { await sleep(1000) continue } const video = await this.getStudyVideoNode(videoNodeID) // 未找到视频 if (!video) { console.log("无视频,停顿5s"); await sleep(5) } else { video.muted = true; await video.play() const videoDur = video.duration if (videoDur <= 0) { console.error("视频无播放时长!") continue } console.log(`开始播放视频,时长为 ${videoDur} 秒`); await this.waitForVideoEnd(video); // 等待视频播放完毕 console.log("视频播放完毕,继续下一个"); //安全间隔 2s await sleep(2); } } if(!this.VIP){ return } //检查学习时间 const studyTime = this.getStudyTime(timeID) const maxTime = this.getMaxStudyTime(timeID) console.log("最大学习时间:", maxTime) console.log("当前学习时长:", studyTime) // 如果学习时间未达到最大值 if (studyTime < maxTime) { console.log("开始挂机,随机点击"); // 每 10 秒随机点击一个节点 const intervalId = setInterval(async () => { // 随机选择一个节点 const randomIndex = Math.floor(Math.random() * studyNodes.length); const randomNode = studyNodes[randomIndex]; console.log(`随机点击节点:${randomNode.innerText}`); randomNode.click(); await sleep(2000) // 再次检查学习时间 const newStudyTime = this.getStudyTime(timeID); console.log("学习时长:", newStudyTime); // 如果学习时间达到最大值,停止定时器 if (newStudyTime >= maxTime) { clearInterval(intervalId); console.log("学习时间已达到最大值,挂机完成!"); this.finish() return 0; } }, 10000); // 每 10 秒执行一次 } else { console.log("学习时间已达到最大值,无需挂机"); this.finish() } } finish() { if (Swal) { Swal.fire({ title: "刷课成功!", text: `学习时间已达到最大值`, icon: 'success', confirmButtonColor: "#FF4DAFFF", confirmButtonText: "确定", }).then((result) => { if (result.isConfirmed) { // 尝试关闭当前页面 try { // window.close(); // 关闭当前页面 } catch (error) { console.error("无法直接关闭页面:", error); // 如果无法直接关闭页面,提示用户手动关闭 Swal.fire({ title: "无法自动关闭页面", text: "请手动关闭此页面。", icon: 'warning', confirmButtonColor: "#FF4DAFFF", confirmButtonText: "确定", }); } } }); } } async waitForVideoEnd(video) { return new Promise(resolve => { const checkInterval = setInterval(async () => { try { if (video && video.paused) { console.log("视频暂停了,重新开始播放..."); await video.play(); } if (!video.src) { console.error("视频源未设置,即将重新加载"); setTimeout(() => { location.reload() }, 5000) } } catch (e) { console.error("checkInterval error:", e); clearInterval(checkInterval); setTimeout(() => { location.reload() }, 2000); } }, 3000); video.addEventListener('ended', () => { clearInterval(checkInterval); resolve() }, {once: true}); // 监听视频结束事件 }); } /** * 获取学习时间,返回秒数 * @param timeId * @returns {number} */ getStudyTime(timeId) { const timeString = document.getElementById(timeId).innerHTML.split('/')[0]; const minute = parseInt(timeString.split('分')[0]) const second = parseInt(timeString.split('分')[1].split('秒')[0]) return minute * 60 + second } /** * 获取最大学习时间 * @param timeId * @returns {number} */ getMaxStudyTime(timeId) { const timeString = document.getElementById(timeId).innerHTML.split('/')[1]; const minute = parseInt(timeString.split('分')[0]) return minute * 60 } /** * 检查 iframe 是否包含视频 * @param {HTMLIFrameElement} iframe - iframe 元素 * @returns {Promise} - 返回是否包含视频 */ checkIframeForVideo(iframe) { return new Promise((resolve) => { // 监听 iframe 的加载完成事件 iframe.addEventListener('load', () => { try { const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; // console.log(iframeDoc.location.href) const iframeUrl = iframeDoc.location.href if (iframeUrl.includes('Play')) { // 视频 resolve(true) } else { resolve(false) } } catch (error) { console.error("无法访问 iframe 内容:", error); resolve(false); } }, {once: true}); // 只监听一次 }); }; /** * 获取视频节点 * @param {string} videoNodeID - 视频元素的 ID * @param {number} timeout - timeout * @returns {Promise} */ getStudyVideoNode(videoNodeID, timeout = 10000) { return new Promise(async (resolve, reject) => { const iframe = document.querySelector('iframe[name="rightFrame"]'); if (!iframe) { console.error("未找到 name='rightFrame' 的 iframe"); resolve(null); } // 检查 iframe 是否包含视频 const hasVideo = await this.checkIframeForVideo(iframe); if (!hasVideo) { console.log("iframe 不包含视频"); resolve(null); return null } else { console.log("包含视频,获取视频节点中..."); } // 获取视频节点 try { const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; // 超时处理 const timeoutId = setTimeout(() => { console.error("获取视频节点超时"); clearInterval(internal); // 清除定时器 resolve(null); // 返回 null }, timeout); // 定期检查视频节点 const internal = setInterval(() => { try { const videoNode = iframeDoc.getElementById(videoNodeID); if (videoNode && videoNode.readyState >= 3) { console.log("video ready!"); clearTimeout(timeoutId); // 清除超时定时器 clearInterval(internal); // 清除检查定时器 resolve(videoNode); // 返回视频节点 } else { console.log("未检查到 video,继续检查..."); } } catch (error) { console.error("检查视频节点时出错:", error); clearTimeout(timeoutId); // 清除超时定时器 clearInterval(internal); // 清除检查定时器 resolve(null); // 返回 null } }, 1000); // 每隔 1 秒检查一次 } catch (error) { console.error("无法访问 iframe 内容:", error); resolve(null); // 返回 null } }) }; /** * 获取目录节点类型 * -1:失败 * 1:有子根节点,无意义,展开子节点 * 2:子节点 * @param studyNode * @returns {number} */ getStudyNodesType(studyNode) { if (!studyNode.id) { return -1 } if (studyNode.id.includes('00000000-0000-0000-0000-000000000000')) { return 1 } else { return 2 } } } class Utils { constructor() { } static flag = 'VIP' static vipText = '高级功能已启用!' static baseText = '您正在使用基础版本,功能可能存在限制' static loadStatus() { try { let VIP = GM_getValue(this.flag) return !!VIP } catch (e) { console.error(e) } return false } static async validateCode(data) { try { console.log(data); let info = document.querySelector('.person').innerText if (!info) { throw new Error("无效的账号信息!") } data.bindInfo = info data.website = "河北-奥鹏" const res = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ 'url': "https://fc-mp-8ba0e2a3-d9c9-45a0-a902-d3bde09f5afd.next.bspapp.com/validCodeFuncCas?" + new URLSearchParams(data), method: 'GET', onload: function (res) { if (res.status === 200) { const result = JSON.parse(res.response) console.log(result) resolve(result) } reject('请求失败:' + res.response) }, onerror: function (err) { console.error(err) reject('请求错误!' + err.toString()) } }) }) if (res.code !== 200) { GM_deleteValue(this.flag) throw new Error('验证失败:' + res.data) } Swal.fire({ title: "高级功能已启用!", text: "校验成功!", icon: 'success', confirmButtonText: '确定', }); GM_setValue(this.flag, true) return res.data } catch (e) { console.error(e) Swal.fire({ title: "验证失败!", text: e.toString(), icon: 'error', confirmButtonText: '确定', }); } } static showLinkSwal() { const link = [ "https://68n.cn/IJ8QB", "https://68n.cn/RM9ob", ] Swal.fire({ title: ' 高级功能解锁', html: `

    需要验证授权码才能使用

    高级版

    1

    需有效授权码激活高级功能模块

    2

    当前账户权限:基础版

    获取授权码步骤:

    1. 点击前往以下链接,获取授权码
    2. 获取授权码链接1
    3. 获取授权码链接2
    `, icon: 'info', confirmButtonText: '前往激活', showCloseButton: true, timer: 30000, customClass: { popup: 'vip-alert-popup', confirmButton: 'vip-confirm-btn' }, willClose: () => { // window.open(link[1]) } }); } } class AuthWindow { constructor() { this.storageKey = 'AuthData'; this.injectGlobalStyles(); this.initDOM(); this.loadPersistedData(); this.show(); // this.startAutomation() } injectGlobalStyles() { GM_addStyle(` .auth-window { position: fixed; bottom: 10px; right: 10px; z-index: 9999; background: white; padding: 24px; border-radius: 12px; box-shadow: 0 6px 30px rgba(0,0,0,0.15); border: 1px solid #e4e7ed; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; min-width: 320px; transform: translateY(20px); opacity: 0; transition: all 0.3s ease; } .auth-window.visible { transform: translateY(0); opacity: 1; } .auth-title { margin: 0 0 16px; font-size: 20px; color: #2c3e50; font-weight: 600; display: flex; align-items: center; gap: 8px; } .auth-version { font-size: 12px; color: #95a5a6; font-weight: normal; } .auth-tip { margin: 0 0 20px; color: #ffbb00; font-size: 14px; font-weight: weight; line-height: 1.5; } .input-group { margin-bottom: 18px; } .input-label { display: block; margin-bottom: 6px; color: #34495e; font-size: 14px; font-weight: 500; } .input-field { width: 80%; padding: 10px 12px; border: 2px solid #e0e0e0; border-radius: 8px; font-size: 14px; transition: border-color 0.2s; } .input-field:focus { outline: none; border-color: #3498db; box-shadow: 0 0 0 3px rgba(52,152,219,0.1); } .auth-button { width: 100%; padding: 12px; background: #3498db; color: white; border: none; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; justify-content: center; gap: 8px; } .auth-button:hover { background: #2980b9; transform: translateY(-1px); } .auth-button:active { transform: translateY(0); } .error-message { color: #e74c3c; font-size: 13px; margin-top: 8px; padding: 8px; background: #fdeded; border-radius: 6px; display: none; animation: shake 0.4s; } @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } } .control-panel { opacity: 1; transform: translateY(10px); transition: all 0.3s ease; } .control-panel.visible { opacity: 1; transform: translateY(0); } .auth-button[disabled] { background: #bdc3c7 !important; cursor: not-allowed; } .auth-window { position: fixed; right: 30px; bottom: 80px; transition: transform 0.3s ease; } .window-toggle:hover .toggle-icon { animation: bounce 0.6s; } .toggle-icon { width: 20px; height: 20px; transition: transform 0.3s ease; } @keyframes bounce { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(4px); } } /* VIP 按钮特效 */ .vip-btn { width: 100%; position: relative; padding: 12px 24px; border: none; border-radius: 8px; background: linear-gradient(135deg, #ffd700 0%, #ffd900 30%, #ffae00 70%, #ff8c00 100%); color: #2c1a00; font-weight: 600; font-family: 'Segoe UI', sans-serif; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); overflow: hidden; box-shadow: 0 4px 15px rgba(255, 174, 0, 0.3); } /* 辉光动画效果 */ .glow-effect::after { content: ''; position: absolute; inset: 0; background: radial-gradient(circle at 50% 0%, rgba(255, 255, 255, 0.4) 0%, transparent 70%); opacity: 0; transition: opacity 0.3s; } /* 悬停交互 */ .vip-btn:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(255, 174, 0, 0.5); } .vip-btn:hover::after { opacity: 1; } /* 点击反馈 */ .vip-btn:active { transform: translateY(1px); box-shadow: 0 2px 8px rgba(255, 174, 0, 0.3); } /* 皇冠图标动画 */ .crown-icon { width: 20px; height: 20px; margin-right: 8px; vertical-align: middle; transition: transform 0.3s; } .vip-btn:hover .crown-icon { transform: rotate(10deg) scale(1.1); } /* 文字渐变特效 */ .vip-text { background: linear-gradient(45deg, #2c1a00, #5a3a00); -webkit-background-clip: text; background-clip: text; color: transparent; display: inline-block; } * 弹窗容器 */ .vip-alert-popup { border: 2px solid #ffd700; border-radius: 12px; background: linear-gradient(145deg, #1a1a1a, #2d2d2d); } /* 标题区域 */ .alert-header { border-bottom: 1px solid #404040; padding-bottom: 12px; margin-bottom: 15px; } .swal-vip-icon { color: #ffd700; font-size: 2.2em; margin-right: 8px; } /* 需求列表 */ .requirements-box { background: rgba(255,215,0,0.1); border-radius: 8px; padding: 15px; margin: 15px 0; } .requirement-item { display: flex; align-items: center; margin: 10px 0; } .number-badge { background: #ffd700; color: #000; width: 24px; height: 24px; border-radius: 50%; text-align: center; margin-right: 12px; font-weight: bold; } /* 状态标签 */ .status-tag { padding: 4px 8px; border-radius: 4px; font-size: 0.9em; } .free-status { background: #ff4444; color: white; } /* 操作引导 */ .action-guide { background: rgba(255,255,255,0.05); padding: 15px; border-radius: 8px; } .step-list li { margin: 8px 0; padding-left: 8px; } .pricing-link { color: #00ff9d !important; text-decoration: underline dotted; transition: all 0.3s; } .pricing-link:hover { color: #00cc7a !important; text-decoration: underline; } /* 确认按钮 */ .vip-confirm-btn { background: linear-gradient(135deg, #ffd700 0%, #ff9900 100%) !important; border: none !important; font-weight: bold !important; transition: transform 0.2s !important; } .vip-confirm-btn:hover { transform: scale(1.05); } `) GM_addStyle(` div.swal2-container { all: initial !important; /* 重置所有继承样式 */ position: fixed !important; z-index: 999999 !important; inset: 0 !important; display: flex !important; align-items: center !important; justify-content: center !important; background: rgba(0,0,0,0.4) !important; } .swal2-popup { all: initial !important; max-width: 600px !important; width: 90vw !important; min-width: 300px !important; position: relative !important; box-sizing: border-box !important; padding: 20px !important; background: white !important; border-radius: 8px !important; font-family: Arial !important; animation: none !important; } @keyframes swal2-show { 0% { transform: scale(0.9); opacity: 0 } 100% { transform: scale(1); opacity: 1 } } `); } initDOM() { this.container = document.createElement('div'); this.container.className = 'auth-window'; // 标题区域 const title = document.createElement('h3'); title.className = 'auth-title'; title.innerHTML = ` 脚本控制台v${GM_info.script.version} `; // 提示信息 const tip = document.createElement('p'); tip.className = 'auth-tip'; tip.textContent = '您正在使用基础版本,功能可能存在限制'; this.tip = tip // 输入框组 // this.phoneInput = this.createInput(' 手机/QQ号', 'text', '#phone'); this.authInput = this.createInput(' 授权密钥', 'password', '#auth'); // 授权链接 const link = [ "https://68n.cn/IJ8QB", "https://68n.cn/RM9ob", ] const authLink1 = this.createLink('authLink1', link[0], '获取授权链接1'); const authLink2 = this.createLink('authLink2', link[1], '获取授权链接2'); // 验证按钮 this.verifyBtn = document.createElement('button'); this.verifyBtn.className = 'auth-button'; this.verifyBtn.innerHTML = ` 验证授权码 `; this.verifyBtn.onclick = () => this.handleVerify(); // 启动控制面板 this.controlPanel = document.createElement('div'); this.controlPanel.className = 'control-panel'; this.controlPanel.style.cssText = ` margin-top: 20px; border-top: 1px solid #eee; padding-top: 16px; `; this.vipBtn = document.createElement('button'); this.vipBtn.className = 'vip-btn glow-effect'; this.vipBtn.innerHTML = ` 高级功能-全自动挂机 `; this.vipBtn.addEventListener('click', () => { this.handleVIPClick() }) // 计时器 this.timerDisplay = document.createElement('div'); this.timerDisplay.className = 'timer'; this.timerDisplay.textContent = '运行时间: 00:00:00'; this.timerDisplay.style.cssText = ` color: #2ecc71; font-size: 13px; margin-bottom: 12px; `; // 开始按钮 this.startBtn = document.createElement('button'); this.startBtn.className = 'auth-button'; this.startBtn.style.backgroundColor = '#2ecc71'; this.startBtn.innerHTML = ` 开始运行-自动化挂机 `; this.startBtn.onclick = () => this.startAutomation(); // 错误提示 this.errorBox = document.createElement('div'); this.errorBox.className = 'error-message'; // 组装结构 this.controlPanel.append( this.vipBtn, this.timerDisplay, this.startBtn ); this.container.append( title, tip, // this.phoneInput.container, this.authInput.container, authLink1, authLink2, this.verifyBtn, this.controlPanel, this.errorBox ); document.body.appendChild(this.container); this.initControlBtn() } initControlBtn() { // 创建控制按钮 this.toggleBtn = document.createElement('button'); this.toggleBtn.className = 'window-toggle'; this.toggleBtn.innerHTML = ` 展开面板 `; this.toggleBtn.style.cssText = ` position: fixed; right: 30px; bottom: 30px; padding: 12px 20px; background: #fff; border: none; border-radius: 30px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); cursor: pointer; display: flex; align-items: center; gap: 8px; transition: all 0.3s ease; z-index: 9999999; `; // 添加交互效果 this.toggleBtn.addEventListener('mouseenter', () => { this.toggleBtn.style.transform = 'translateY(-2px)'; this.toggleBtn.style.boxShadow = '0 6px 16px rgba(0,0,0,0.2)'; }); this.toggleBtn.addEventListener('mouseleave', () => { this.toggleBtn.style.transform = 'none'; this.toggleBtn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)'; }); // 点击事件处理 this.toggleBtn.onclick = () => { const isVisible = this.container.style.display !== 'none'; this.container.style.display = isVisible ? 'none' : 'block'; // 更新按钮状态 this.toggleBtn.querySelector('.toggle-icon').style.transform = isVisible ? 'rotate(180deg)' : 'none'; this.toggleBtn.querySelector('.toggle-text').textContent = isVisible ? '展开面板' : '收起面板'; // 添加动画效果 if (!isVisible) { this.container.animate([ {opacity: 0, transform: 'translateY(20px)'}, {opacity: 1, transform: 'none'} ], {duration: 300, easing: 'ease-out'}); } }; document.body.appendChild(this.toggleBtn); } startAutomation(callback) { if (!this.isRunning) { this.startTime = Date.now(); this.isRunning = true; this.startBtn.innerHTML = ` 运行中... `; this.startBtn.style.backgroundColor = '#e67e22'; this.startBtn.disabled = true; // 启动计时器 this.timer = setInterval(() => { const elapsed = Date.now() - this.startTime; const hours = Math.floor(elapsed / 3600000); const minutes = Math.floor((elapsed % 3600000) / 60000); const seconds = Math.floor((elapsed % 60000) / 1000); this.timerDisplay.textContent = `运行时间: ${hours.toString().padStart(2, '0')}:` + `${minutes.toString().padStart(2, '0')}:` + `${seconds.toString().padStart(2, '0')}`; }, 1000); // 触发自动化任务 if (typeof callback === 'function') { callback() } if (this.begin && typeof this.begin === 'function') { this.begin() } } } createInput(labelText, type, id) { const container = document.createElement('div'); container.className = 'input-group'; const label = document.createElement('label'); label.className = 'input-label'; label.textContent = labelText; label.htmlFor = id; const input = document.createElement('input'); input.className = 'input-field'; input.type = type; input.id = id; input.maxLength = 16 container.appendChild(label); container.appendChild(input); return {container, input}; } createLink(id, link, name) { const authLink = document.createElement('a'); authLink.id = id; authLink.className = 'auth-link'; authLink.href = link; authLink.target = '_blank'; authLink.textContent = name; authLink.style.cssText = ` display: block; margin: 12px 0; color: #3498db; text-decoration: none; font-size: 13px; transition: opacity 0.2s; `; authLink.addEventListener('mouseenter', () => { authLink.style.opacity = '0.8'; authLink.style.textDecoration = 'underline'; }); authLink.addEventListener('mouseleave', () => { authLink.style.opacity = '1'; authLink.style.textDecoration = 'none'; }); return authLink } show() { setTimeout(() => { this.container.classList.add('visible'); }, 100); } showError(message) { this.errorBox.textContent = message; this.errorBox.style.display = 'block'; setTimeout(() => { this.errorBox.style.display = 'none'; }, 5000); } async handleVerify() { const data = { // phone: this.phoneInput.input.value, key: this.authInput.input.value }; console.log(data); if (!data.key || !(/^[A-Z0-9]{16}$/).test(data.key)) { Swal.fire({ title: "授权码不正确,应为16位", text: "请正确输入!", icon: 'info', confirmButtonText: '确定', }); return } // 触发验证回调 if (this.onVerify) { if (await this.onVerify(data)) { GM_setValue(this.storageKey, JSON.stringify(data)) } else { } } } handleVIPClick() { if (this.vipCallback) { this.vipCallback() } else { Swal.fire({ title: "提示", text: "请在视频播放页面使用!", icon: 'info', confirmButtonText: '确定', willClose: () => { console.log(' 用户确认错误,脚本已停止'); } }); } } loadPersistedData() { let saved = GM_getValue(this.storageKey); if (saved) { saved = JSON.parse(saved) // this.phoneInput.input.value = saved.phone || ''; this.authInput.input.value = saved.key || ''; } } hide() { this.container.style.display = 'none'; } // get phone() { // return this.phoneInput.input.value; // } // set phone(value) { // this.phoneInput.input.value = value; // } get key() { return this.authInput.input.value; } set key(value) { // this.authInput.input.value = value; } setTip(text) { this.tip.innerText = text } // 验证回调函数 setOnVerifyCallback(callback) { this.onVerify = callback; } setOnBegin(callback) { this.begin = callback; } setOnVIP(callback) { this.vipCallback = callback; } } new Runner() } } // 高等教育出版社-2024中小学 // 基础教育教师培训网 class Chinabett { constructor() { } run(config) { this.setupCoreFeatures(config); } setupCoreFeatures({refreshInterval}) { class Runner { constructor() { this.runner = null this.run() } run() { const url = location.href; if (url.includes("studyduration/index")) { this.runner = new Course("channel-cas") // this.runner.run() } } } class Course { constructor(channel = "channel-my") { this.panel = new AuthWindow() this.channel = channel this.VIP = false this.running = false this.init() } init() { this.panel.setOnVerifyCallback(async (data) => { this.url = await Utils.validateCode(data) if (this.url) { this.panel.setTip(Utils.vipText) this.VIP = true return true } }) this.panel.setOnBegin(() => { if (!this.running) { this.running = true console.log("运行时:", this.VIP) this.run().then(r => { this.running = false }) } }) this.panel.setOnVIP(async () => { if(!this.url){ await this.panel.handleVerify() } await this.runVIP() }) this.loadVIPStatus() try { Swal.fire({ title: "提示", text: "脚本3s后自动开始", icon: 'info', timer: 3000, confirmButtonText: '确定', willClose: () => { this.panel.startAutomation() } }); } catch (e) { console.error(e) this.panel.startAutomation() } } loadVIPStatus() { if (Utils.loadStatus()) { this.panel.setTip(Utils.vipText) this.VIP = true } else { this.panel.setTip(Utils.baseText) this.VIP = false } console.log("VIP:", this.VIP) } async runVIP() { try { if (!this.VIP) { Utils.showLinkSwal() console.log("需要授权码!") return } if (window.VIPRunning) { console.log("VIP Running"); Swal.fire({ title: "课程已在刷取中,请等待...", text: "注意,请在视频播放时刷取!否则可能不生效!", icon: 'info', confirmButtonText: '确定', willClose: () => { } }); return } Swal.fire({ title: "刷课已开始", text: "注意,请在视频播放时刷取!否则可能不生效!刷完后请刷新页面!", icon: 'info', confirmButtonText: '确定', willClose: () => { } }); let jsCode = GM_getValue("jsCode") if (!jsCode) { jsCode = await Utils.getJsCode(this.url) } eval(jsCode) console.log(window.VIP) await window.VIP() } catch (error) { console.error(error) Swal.fire({ title: "高级功能执行失败!", text: "若一直失败,请联系进行售后处理!", icon: 'error', confirmButtonText: '确定', allowOutsideClick: false, willClose: () => { console.log(' 用户确认错误,脚本已停止'); } }); } } async run() { const catalogList = await this.getStudyNode('dd a', 'nodeList'); console.log(this.VIP) if (!this.VIP) { Swal.fire({ title: '当前是基础版', text: '脚本只会常速播放完列表视频!', icon: 'info', confirmButtonText: '确定', timer: 5000, willClose: () => { console.log(this.VIP) } }); } let i = 0 let video for (i; i < catalogList.length; i++) { if (catalogList[i].className !== "dd_active") { continue } await sleep(2000) video = await this.getStudyNode('video') video.volum = 0 video.muted = true await video.play() /*setInterval(() => { if (video && video.paused) { video.play() } }, 5000)*/ await this.waitForVideoEnd(video) if (!this.VIP && i > 3) { break } try { $(unsafeWindow).off('beforeunload'); setTimeout(() => { $(unsafeWindow).off('beforeunload'); catalogList[i + 1].click() }, 1000) } catch (err) { console.error(err) } } const onClose = () => { window.close() } if (!this.VIP && i !== catalogList.length - 1) { Swal.fire({ title: '当前是基础版', text: '脚本已自动学习完前几个视频,若有需要请获取授权码!', icon: 'info', confirmButtonText: '确定', timer: 0, willClose: () => { } }); } else { Swal.fire({ title: '当前课程完成!', text: '脚本将在10s后关闭此页面!', icon: 'success', confirmButtonText: '确定', timer: 10000, willClose: () => { onClose() } }); } } async waitForVideoEnd(video) { return new Promise(resolve => { const checkInterval = setInterval(async () => { try { if (video && video.paused) { console.log("视频暂停了,重新开始播放..."); await video.play(); } if (!video.src) { console.error("视频源未设置,即将重新加载"); setTimeout(() => { location.reload() }, 5000) } } catch (e) { console.error("checkInterval error:", e); clearInterval(checkInterval); setTimeout(() => { location.reload() }, 2000); } }, 3000); video.addEventListener('ended', () => { clearInterval(checkInterval); resolve() }, {once: true}); // 监听视频结束事件 }); } getStudyNode(selector, type = 'node', timeout = 10000) { return new Promise((resolve, reject) => { if (!['node', 'nodeList'].includes(type)) { console.error('Invalid type parameter. Expected "node" or "nodeList"'); reject('Invalid type parameter. Expected "node" or "nodeList"'); } const cleanup = (timeoutId, intervalId) => { clearTimeout(timeoutId); clearInterval(intervalId); }; const handleSuccess = (result, timeoutId, intervalId) => { console.log(`${selector} ready!`); cleanup(timeoutId, intervalId); resolve(result); }; const handleFailure = (timeoutId, intervalId) => { cleanup(timeoutId, intervalId); resolve(null); }; const checkNode = () => { try { let nodes; if (type === 'node') { nodes = document.querySelector(selector); return nodes?.readyState >= 3 ? nodes : null; } nodes = document.querySelectorAll(selector); return nodes.length > 0 ? nodes : null; } catch (error) { console.error('节点检查错误:', error); reject('节点检查错误:', error) } }; const intervalId = setInterval(() => { const result = checkNode(); if (result) { handleSuccess(result, timeoutId, intervalId); } else { console.log(`等待节点: ${selector}...`); } }, 3000); const timeoutId = setTimeout(() => { console.error(`节点获取超时: ${selector}`); handleFailure(timeoutId, intervalId); }, timeout); }); } } class Utils { constructor() { } static flag = 'VIP' static vipText = '高级功能已启用!' static baseText = '您正在使用基础版本,功能可能存在限制' static loadStatus() { try { let VIP = GM_getValue(this.flag) return !!VIP } catch (e) { console.error(e) } return false } static async validateCode(data) { try { console.log(data); let info = $("#hidUserId").val(); if (!info) { throw new Error("无效的账号信息!") } data.bindInfo = 'userId_' + info data.website = "河北-高教社-基础教育教师" // console.log(data); // return const res = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ 'url': "https://fc-mp-8ba0e2a3-d9c9-45a0-a902-d3bde09f5afd.next.bspapp.com/validCodeFuncCas?" + new URLSearchParams(data), method: 'GET', onload: function (res) { if (res.status === 200) { const result = JSON.parse(res.response) console.log(result) resolve(result) } reject('请求失败:' + res.response) }, onerror: function (err) { console.error(err) reject('请求错误!' + err.toString()) } }) }) if (res.code !== 200) { GM_deleteValue(this.flag) throw new Error('验证失败:' + res.data) } Swal.fire({ title: "高级功能已启用!", text: "校验成功!", icon: 'success', confirmButtonText: '确定', }); GM_setValue(this.flag, true) return res.data } catch (e) { console.error(e) Swal.fire({ title: "验证失败!", text: e.toString(), icon: 'error', confirmButtonText: '确定', }); } } static async getJsCode(url) { try { let code = GM_getValue('jsCode') if (!code) { const jsUrl = url //获取js文件,然后在这里执行,然后获得结果 const jsCode = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ 'url': jsUrl, method: 'GET', onload: function (res) { console.log(res) if (res.status === 200) { const result = (res.responseText) // console.log(result) resolve(result) } else { reject('服务器拒绝:' + res.response) } }, onerror: function (err) { console.error(err) reject('请求错误!' + err.toString()) } }) }) code = jsCode .replace(/\\/g, '\\\\') .replace(/'/g, '\'') .replace(/"/g, '\"') GM_setValue('jsCode', code) } return code } catch (error) { console.error('远程加载失败:', error); throw new Error("远程加载失败") } } static showLinkSwal() { const link = [ "https://68n.cn/IJ8QB", "https://68n.cn/RM9ob", ] Swal.fire({ title: ' 高级功能解锁', html: `

    需要验证授权码才能使用

    高级版

    1

    需有效授权码激活高级功能模块

    2

    当前账户权限:基础版

    获取授权码步骤:

    1. 点击前往以下链接,获取授权码
    2. 获取授权码链接1
    3. 获取授权码链接2
    `, icon: 'info', confirmButtonText: '前往激活', showCloseButton: true, timer: 30000, customClass: { popup: 'vip-alert-popup', confirmButton: 'vip-confirm-btn' }, willClose: () => { window.open(link[1]) } }); } } class AuthWindow { constructor() { this.storageKey = 'AuthData'; this.injectGlobalStyles(); this.initDOM(); this.loadPersistedData(); this.show(); // this.startAutomation() } injectGlobalStyles() { GM_addStyle(` .auth-window { position: fixed; bottom: 10px; right: 10px; z-index: 9999; background: white; padding: 24px; border-radius: 12px; box-shadow: 0 6px 30px rgba(0,0,0,0.15); border: 1px solid #e4e7ed; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; min-width: 320px; transform: translateY(20px); opacity: 0; transition: all 0.3s ease; } .auth-window.visible { transform: translateY(0); opacity: 1; } .auth-title { margin: 0 0 16px; font-size: 20px; color: #2c3e50; font-weight: 600; display: flex; align-items: center; gap: 8px; } .auth-version { font-size: 12px; color: #95a5a6; font-weight: normal; } .auth-tip { margin: 0 0 20px; color: #ffbb00; font-size: 14px; font-weight: weight; line-height: 1.5; } .input-group { margin-bottom: 18px; } .input-label { display: block; margin-bottom: 6px; color: #34495e; font-size: 14px; font-weight: 500; } .input-field { width: 80%; padding: 10px 12px; border: 2px solid #e0e0e0; border-radius: 8px; font-size: 14px; transition: border-color 0.2s; } .input-field:focus { outline: none; border-color: #3498db; box-shadow: 0 0 0 3px rgba(52,152,219,0.1); } .auth-button { width: 100%; padding: 12px; background: #3498db; color: white; border: none; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; justify-content: center; gap: 8px; } .auth-button:hover { background: #2980b9; transform: translateY(-1px); } .auth-button:active { transform: translateY(0); } .error-message { color: #e74c3c; font-size: 13px; margin-top: 8px; padding: 8px; background: #fdeded; border-radius: 6px; display: none; animation: shake 0.4s; } @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } } .control-panel { opacity: 1; transform: translateY(10px); transition: all 0.3s ease; } .control-panel.visible { opacity: 1; transform: translateY(0); } .auth-button[disabled] { background: #bdc3c7 !important; cursor: not-allowed; } .auth-window { position: fixed; right: 30px; bottom: 80px; transition: transform 0.3s ease; } .window-toggle:hover .toggle-icon { animation: bounce 0.6s; } .toggle-icon { width: 20px; height: 20px; transition: transform 0.3s ease; } @keyframes bounce { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(4px); } } /* VIP 按钮特效 */ .vip-btn { width: 100%; position: relative; padding: 12px 24px; border: none; border-radius: 8px; background: linear-gradient(135deg, #ffd700 0%, #ffd900 30%, #ffae00 70%, #ff8c00 100%); color: #2c1a00; font-weight: 600; font-family: 'Segoe UI', sans-serif; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); overflow: hidden; box-shadow: 0 4px 15px rgba(255, 174, 0, 0.3); } /* 辉光动画效果 */ .glow-effect::after { content: ''; position: absolute; inset: 0; background: radial-gradient(circle at 50% 0%, rgba(255, 255, 255, 0.4) 0%, transparent 70%); opacity: 0; transition: opacity 0.3s; } /* 悬停交互 */ .vip-btn:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(255, 174, 0, 0.5); } .vip-btn:hover::after { opacity: 1; } /* 点击反馈 */ .vip-btn:active { transform: translateY(1px); box-shadow: 0 2px 8px rgba(255, 174, 0, 0.3); } /* 皇冠图标动画 */ .crown-icon { width: 20px; height: 20px; margin-right: 8px; vertical-align: middle; transition: transform 0.3s; } .vip-btn:hover .crown-icon { transform: rotate(10deg) scale(1.1); } /* 文字渐变特效 */ .vip-text { background: linear-gradient(45deg, #2c1a00, #5a3a00); -webkit-background-clip: text; background-clip: text; color: transparent; display: inline-block; } * 弹窗容器 */ .vip-alert-popup { border: 2px solid #ffd700; border-radius: 12px; background: linear-gradient(145deg, #1a1a1a, #2d2d2d); } /* 标题区域 */ .alert-header { border-bottom: 1px solid #404040; padding-bottom: 12px; margin-bottom: 15px; } .swal-vip-icon { color: #ffd700; font-size: 2.2em; margin-right: 8px; } /* 需求列表 */ .requirements-box { background: rgba(255,215,0,0.1); border-radius: 8px; padding: 15px; margin: 15px 0; } .requirement-item { display: flex; align-items: center; margin: 10px 0; } .number-badge { background: #ffd700; color: #000; width: 24px; height: 24px; border-radius: 50%; text-align: center; margin-right: 12px; font-weight: bold; } /* 状态标签 */ .status-tag { padding: 4px 8px; border-radius: 4px; font-size: 0.9em; } .free-status { background: #ff4444; color: white; } /* 操作引导 */ .action-guide { background: rgba(255,255,255,0.05); padding: 15px; border-radius: 8px; } .step-list li { margin: 8px 0; padding-left: 8px; } .pricing-link { color: #00ff9d !important; text-decoration: underline dotted; transition: all 0.3s; } .pricing-link:hover { color: #00cc7a !important; text-decoration: underline; } /* 确认按钮 */ .vip-confirm-btn { background: linear-gradient(135deg, #ffd700 0%, #ff9900 100%) !important; border: none !important; font-weight: bold !important; transition: transform 0.2s !important; } .vip-confirm-btn:hover { transform: scale(1.05); } `) } initDOM() { this.container = document.createElement('div'); this.container.className = 'auth-window'; // 标题区域 const title = document.createElement('h3'); title.className = 'auth-title'; title.innerHTML = ` 脚本控制台v${GM_info.script.version} `; // 提示信息 const tip = document.createElement('p'); tip.className = 'auth-tip'; tip.textContent = '您正在使用基础版本,功能可能存在限制'; this.tip = tip // 输入框组 // this.phoneInput = this.createInput(' 手机/QQ号', 'text', '#phone'); this.authInput = this.createInput(' 授权密钥', 'password', '#auth'); // 授权链接 const link = [ "https://68n.cn/IJ8QB", "https://68n.cn/RM9ob", ] const authLink1 = this.createLink('authLink1', link[0], '获取授权链接1'); const authLink2 = this.createLink('authLink2', link[1], '获取授权链接2'); // 验证按钮 this.verifyBtn = document.createElement('button'); this.verifyBtn.className = 'auth-button'; this.verifyBtn.innerHTML = ` 验证授权码 `; this.verifyBtn.onclick = () => this.handleVerify(); // 启动控制面板 this.controlPanel = document.createElement('div'); this.controlPanel.className = 'control-panel'; this.controlPanel.style.cssText = ` margin-top: 20px; border-top: 1px solid #eee; padding-top: 16px; `; this.vipBtn = document.createElement('button'); this.vipBtn.className = 'vip-btn glow-effect'; this.vipBtn.innerHTML = ` 高级功能-极速刷课(视频播放时使用) `; this.vipBtn.addEventListener('click', () => { this.handleVIPClick() }) // 计时器 this.timerDisplay = document.createElement('div'); this.timerDisplay.className = 'timer'; this.timerDisplay.textContent = '运行时间: 00:00:00'; this.timerDisplay.style.cssText = ` color: #2ecc71; font-size: 13px; margin-bottom: 12px; `; // 开始按钮 this.startBtn = document.createElement('button'); this.startBtn.className = 'auth-button'; this.startBtn.style.backgroundColor = '#2ecc71'; this.startBtn.innerHTML = ` 开始运行-自动化挂机 `; this.startBtn.onclick = () => this.startAutomation(); // 错误提示 this.errorBox = document.createElement('div'); this.errorBox.className = 'error-message'; // 组装结构 this.controlPanel.append( this.vipBtn, this.timerDisplay, this.startBtn ); this.container.append( title, tip, // this.phoneInput.container, this.authInput.container, authLink1, authLink2, this.verifyBtn, this.controlPanel, this.errorBox ); document.body.appendChild(this.container); this.initControlBtn() } initControlBtn() { // 创建控制按钮 this.toggleBtn = document.createElement('button'); this.toggleBtn.className = 'window-toggle'; this.toggleBtn.innerHTML = ` 展开面板 `; this.toggleBtn.style.cssText = ` position: fixed; right: 30px; bottom: 30px; padding: 12px 20px; background: #fff; border: none; border-radius: 30px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); cursor: pointer; display: flex; align-items: center; gap: 8px; transition: all 0.3s ease; z-index: 9999999; `; // 添加交互效果 this.toggleBtn.addEventListener('mouseenter', () => { this.toggleBtn.style.transform = 'translateY(-2px)'; this.toggleBtn.style.boxShadow = '0 6px 16px rgba(0,0,0,0.2)'; }); this.toggleBtn.addEventListener('mouseleave', () => { this.toggleBtn.style.transform = 'none'; this.toggleBtn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)'; }); // 点击事件处理 this.toggleBtn.onclick = () => { const isVisible = this.container.style.display !== 'none'; this.container.style.display = isVisible ? 'none' : 'block'; // 更新按钮状态 this.toggleBtn.querySelector('.toggle-icon').style.transform = isVisible ? 'rotate(180deg)' : 'none'; this.toggleBtn.querySelector('.toggle-text').textContent = isVisible ? '展开面板' : '收起面板'; // 添加动画效果 if (!isVisible) { this.container.animate([ {opacity: 0, transform: 'translateY(20px)'}, {opacity: 1, transform: 'none'} ], {duration: 300, easing: 'ease-out'}); } }; document.body.appendChild(this.toggleBtn); } startAutomation(callback) { if (!this.isRunning) { this.startTime = Date.now(); this.isRunning = true; this.startBtn.innerHTML = ` 运行中... `; this.startBtn.style.backgroundColor = '#e67e22'; this.startBtn.disabled = true; // 启动计时器 this.timer = setInterval(() => { const elapsed = Date.now() - this.startTime; const hours = Math.floor(elapsed / 3600000); const minutes = Math.floor((elapsed % 3600000) / 60000); const seconds = Math.floor((elapsed % 60000) / 1000); this.timerDisplay.textContent = `运行时间: ${hours.toString().padStart(2, '0')}:` + `${minutes.toString().padStart(2, '0')}:` + `${seconds.toString().padStart(2, '0')}`; }, 1000); // 触发自动化任务 if (typeof callback === 'function') { callback() } if (this.begin && typeof this.begin === 'function') { this.begin() } } } createInput(labelText, type, id) { const container = document.createElement('div'); container.className = 'input-group'; const label = document.createElement('label'); label.className = 'input-label'; label.textContent = labelText; label.htmlFor = id; const input = document.createElement('input'); input.className = 'input-field'; input.type = type; input.id = id; input.maxLength = 16 container.appendChild(label); container.appendChild(input); return {container, input}; } createLink(id, link, name) { const authLink = document.createElement('a'); authLink.id = id; authLink.className = 'auth-link'; authLink.href = link; authLink.target = '_blank'; authLink.textContent = name; authLink.style.cssText = ` display: block; margin: 12px 0; color: #3498db; text-decoration: none; font-size: 13px; transition: opacity 0.2s; `; authLink.addEventListener('mouseenter', () => { authLink.style.opacity = '0.8'; authLink.style.textDecoration = 'underline'; }); authLink.addEventListener('mouseleave', () => { authLink.style.opacity = '1'; authLink.style.textDecoration = 'none'; }); return authLink } show() { setTimeout(() => { this.container.classList.add('visible'); }, 100); } showError(message) { this.errorBox.textContent = message; this.errorBox.style.display = 'block'; setTimeout(() => { this.errorBox.style.display = 'none'; }, 5000); } async handleVerify() { const data = { // phone: this.phoneInput.input.value, key: this.authInput.input.value }; console.log(data); if (!data.key || !(/^[A-Z0-9]{16}$/).test(data.key)) { Swal.fire({ title: "授权码不正确,应为16位", text: "请正确输入!", icon: 'info', confirmButtonText: '确定', }); return } // 触发验证回调 if (this.onVerify) { if (await this.onVerify(data)) { GM_setValue(this.storageKey, JSON.stringify(data)) } else { } } } handleVIPClick() { if (this.vipCallback) { this.vipCallback() } else { Swal.fire({ title: "提示", text: "请在视频播放页面使用!", icon: 'info', confirmButtonText: '确定', willClose: () => { console.log(' 用户确认错误,脚本已停止'); } }); } } loadPersistedData() { let saved = GM_getValue(this.storageKey); if (saved) { saved = JSON.parse(saved) // this.phoneInput.input.value = saved.phone || ''; this.authInput.input.value = saved.key || ''; } } hide() { this.container.style.display = 'none'; } get key() { return this.authInput.input.value; } set key(value) { // this.authInput.input.value = value; } setTip(text) { this.tip.innerText = text } setOnVerifyCallback(callback) { this.onVerify = callback; } setOnBegin(callback) { this.begin = callback; } setOnVIP(callback) { this.vipCallback = callback; } } new Runner() } } const sleep = function (time) { return new Promise(resolve => setTimeout(resolve, time)); } new ScriptCore()